1 // Copyright 2002 The Trustees of Indiana University.
2 
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 //  Boost.MultiArray Library
8 //  Authors: Ronald Garcia
9 //           Jeremy Siek
10 //           Andrew Lumsdaine
11 //  See http://www.boost.org/libs/multi_array for documentation.
12 
13 #ifndef BOOST_INDEX_RANGE_RG071801_HPP
14 #define BOOST_INDEX_RANGE_RG071801_HPP
15 
16 #include <boost/config.hpp>
17 #include <utility>
18 #include <boost/limits.hpp>
19 
20 // For representing intervals, also with stride.
21 // A degenerate range is a range with one element.
22 
23 // Thanks to Doug Gregor for the really cool idea of using the
24 // comparison operators to express various interval types!
25 
26 // Internally, we represent the interval as half-open.
27 
28 namespace boost {
29 namespace detail {
30 namespace multi_array {
31 
32   template <typename Index,typename SizeType>
33   class index_range {
34   public:
35     typedef Index index;
36     typedef SizeType size_type;
37 
index_range()38     index_range()
39     {
40       start_ = from_start();
41       finish_ = to_end();
42       stride_ = 1;
43       degenerate_ = false;
44     }
45 
index_range(index pos)46     explicit index_range(index pos)
47     {
48       start_ = pos;
49       finish_ = pos;
50       stride_ = 1;
51       degenerate_ = true;
52     }
53 
index_range(index start,index finish,index stride=1)54     explicit index_range(index start, index finish, index stride=1)
55       : start_(start), finish_(finish), stride_(stride),
56         degenerate_(false)
57     { }
58 
59 
60     // These are for chaining assignments to an index_range
start(index s)61     index_range& start(index s) {
62       start_ = s;
63       degenerate_ = (start_ == finish_);
64       return *this;
65     }
66 
finish(index f)67     index_range& finish(index f) {
68       finish_ = f;
69       degenerate_ = (start_ == finish_);
70       return *this;
71     }
72 
stride(index s)73     index_range& stride(index s) { stride_ = s; return *this; }
74 
start() const75     index start() const
76     {
77       return start_;
78     }
79 
get_start(index low_index_range=0) const80     index get_start(index low_index_range = 0) const
81     {
82       if (start_ == from_start())
83         return low_index_range;
84       return start_;
85     }
86 
finish() const87     index finish() const
88     {
89       return finish_;
90     }
91 
get_finish(index high_index_range=0) const92     index get_finish(index high_index_range = 0) const
93     {
94       if (finish_ == to_end())
95         return high_index_range;
96       return finish_;
97     }
98 
size(index recommended_length=0) const99     size_type size(index recommended_length = 0) const
100     {
101       if ((start_ == from_start()) || (finish_ == to_end()))
102         return recommended_length;
103       else
104         return (finish_ - start_) / stride_;
105     }
106 
stride() const107     index stride() const { return stride_; }
108 
is_ascending_contiguous() const109     bool is_ascending_contiguous() const
110     {
111       return (start_ < finish_) && is_unit_stride();
112     }
113 
set_index_range(index start,index finish,index stride=1)114     void set_index_range(index start, index finish, index stride=1)
115     {
116       start_ = start;
117       finish_ = finish;
118       stride_ = stride;
119     }
120 
all()121     static index_range all()
122     { return index_range(from_start(), to_end(), 1); }
123 
is_unit_stride() const124     bool is_unit_stride() const
125     { return stride_ == 1; }
126 
is_degenerate() const127     bool is_degenerate() const { return degenerate_; }
128 
operator -(index shift) const129     index_range operator-(index shift) const
130     {
131       return index_range(start_ - shift, finish_ - shift, stride_);
132     }
133 
operator +(index shift) const134     index_range operator+(index shift) const
135     {
136       return index_range(start_ + shift, finish_ + shift, stride_);
137     }
138 
operator [](unsigned i) const139     index operator[](unsigned i) const
140     {
141       return start_ + i * stride_;
142     }
143 
operator ()(unsigned i) const144     index operator()(unsigned i) const
145     {
146       return start_ + i * stride_;
147     }
148 
149     // add conversion to std::slice?
150 
151   private:
from_start()152     static index from_start()
153       { return (std::numeric_limits<index>::min)(); }
154 
to_end()155     static index to_end()
156       { return (std::numeric_limits<index>::max)(); }
157   public:
158     index start_, finish_, stride_;
159     bool degenerate_;
160   };
161 
162   // Express open and closed interval end-points using the comparison
163   // operators.
164 
165   // left closed
166   template <typename Index, typename SizeType>
167   inline index_range<Index,SizeType>
operator <=(Index s,const index_range<Index,SizeType> & r)168   operator<=(Index s, const index_range<Index,SizeType>& r)
169   {
170     return index_range<Index,SizeType>(s, r.finish(), r.stride());
171   }
172 
173   // left open
174   template <typename Index, typename SizeType>
175   inline index_range<Index,SizeType>
operator <(Index s,const index_range<Index,SizeType> & r)176   operator<(Index s, const index_range<Index,SizeType>& r)
177   {
178     return index_range<Index,SizeType>(s + 1, r.finish(), r.stride());
179   }
180 
181   // right open
182   template <typename Index, typename SizeType>
183   inline index_range<Index,SizeType>
operator <(const index_range<Index,SizeType> & r,Index f)184   operator<(const index_range<Index,SizeType>& r, Index f)
185   {
186     return index_range<Index,SizeType>(r.start(), f, r.stride());
187   }
188 
189   // right closed
190   template <typename Index, typename SizeType>
191   inline index_range<Index,SizeType>
operator <=(const index_range<Index,SizeType> & r,Index f)192   operator<=(const index_range<Index,SizeType>& r, Index f)
193   {
194     return index_range<Index,SizeType>(r.start(), f + 1, r.stride());
195   }
196 
197 } // namespace multi_array
198 } // namespace detail
199 } // namespace boost
200 
201 #endif // BOOST_INDEX_RANGE_RG071801_HPP
202