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 SUBARRAY_RG071801_HPP
14 #define SUBARRAY_RG071801_HPP
15 
16 //
17 // subarray.hpp - used to implement standard operator[] on
18 // multi_arrays
19 //
20 
21 #include "boost/multi_array/base.hpp"
22 #include "boost/multi_array/concept_checks.hpp"
23 #include "boost/limits.hpp"
24 #include "boost/type.hpp"
25 #include <algorithm>
26 #include <cstddef>
27 #include <functional>
28 
29 namespace boost {
30 namespace detail {
31 namespace multi_array {
32 
33 //
34 // const_sub_array
35 //    multi_array's proxy class to allow multiple overloads of
36 //    operator[] in order to provide a clean multi-dimensional array
37 //    interface.
38 template <typename T, std::size_t NumDims, typename TPtr>
39 class const_sub_array :
40   public boost::detail::multi_array::multi_array_impl_base<T,NumDims>
41 {
42   typedef boost::detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
43 public:
44   typedef typename super_type::value_type value_type;
45   typedef typename super_type::const_reference const_reference;
46   typedef typename super_type::const_iterator const_iterator;
47   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
48   typedef typename super_type::element element;
49   typedef typename super_type::size_type size_type;
50   typedef typename super_type::difference_type difference_type;
51   typedef typename super_type::index index;
52   typedef typename super_type::extent_range extent_range;
53 
54   // template typedefs
55   template <std::size_t NDims>
56   struct const_array_view {
57     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
58   };
59 
60   template <std::size_t NDims>
61   struct array_view {
62     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
63   };
64 
65   // Allow default copy constructor as well.
66 
67   template <typename OPtr>
const_sub_array(const const_sub_array<T,NumDims,OPtr> & rhs)68   const_sub_array (const const_sub_array<T,NumDims,OPtr>& rhs) :
69     base_(rhs.base_), extents_(rhs.extents_), strides_(rhs.strides_),
70     index_base_(rhs.index_base_) {
71   }
72 
73   // const_sub_array always returns const types, regardless of its own
74   // constness.
operator [](index idx) const75   const_reference operator[](index idx) const {
76     return super_type::access(boost::type<const_reference>(),
77                               idx,base_,shape(),strides(),index_bases());
78   }
79 
80   template <typename IndexList>
operator ()(const IndexList & indices) const81   const element& operator()(const IndexList& indices) const {
82     return super_type::access_element(boost::type<const element&>(),
83                                       origin(),
84                                       indices,strides());
85   }
86 
87   // see generate_array_view in base.hpp
88 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
89   template <int NDims>
90 #else
91   template <int NumDims, int NDims> // else ICE
92 #endif // BOOST_MSVC
93   typename const_array_view<NDims>::type
operator [](const boost::detail::multi_array::index_gen<NumDims,NDims> & indices) const94   operator[](const boost::detail::multi_array::
95              index_gen<NumDims,NDims>& indices)
96     const {
97     typedef typename const_array_view<NDims>::type return_type;
98     return
99       super_type::generate_array_view(boost::type<return_type>(),
100                                       indices,
101                                       shape(),
102                                       strides(),
103                                       index_bases(),
104                                       base_);
105   }
106 
107   template <typename OPtr>
operator <(const const_sub_array<T,NumDims,OPtr> & rhs) const108   bool operator<(const const_sub_array<T,NumDims,OPtr>& rhs) const {
109     return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
110   }
111 
112   template <typename OPtr>
operator ==(const const_sub_array<T,NumDims,OPtr> & rhs) const113   bool operator==(const const_sub_array<T,NumDims,OPtr>& rhs) const {
114     if(std::equal(shape(),shape()+num_dimensions(),rhs.shape()))
115       return std::equal(begin(),end(),rhs.begin());
116     else return false;
117   }
118 
119   template <typename OPtr>
operator !=(const const_sub_array<T,NumDims,OPtr> & rhs) const120   bool operator!=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
121     return !(*this == rhs);
122   }
123 
124   template <typename OPtr>
operator >(const const_sub_array<T,NumDims,OPtr> & rhs) const125   bool operator>(const const_sub_array<T,NumDims,OPtr>& rhs) const {
126     return rhs < *this;
127   }
128 
129   template <typename OPtr>
operator <=(const const_sub_array<T,NumDims,OPtr> & rhs) const130   bool operator<=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
131     return !(*this > rhs);
132   }
133 
134   template <typename OPtr>
operator >=(const const_sub_array<T,NumDims,OPtr> & rhs) const135   bool operator>=(const const_sub_array<T,NumDims,OPtr>& rhs) const {
136     return !(*this < rhs);
137   }
138 
begin() const139   const_iterator begin() const {
140     return const_iterator(*index_bases(),origin(),
141                           shape(),strides(),index_bases());
142   }
143 
end() const144   const_iterator end() const {
145     return const_iterator(*index_bases()+(index)*shape(),origin(),
146                           shape(),strides(),index_bases());
147   }
148 
rbegin() const149   const_reverse_iterator rbegin() const {
150     return const_reverse_iterator(end());
151   }
152 
rend() const153   const_reverse_iterator rend() const {
154     return const_reverse_iterator(begin());
155   }
156 
origin() const157   TPtr origin() const { return base_; }
size() const158   size_type size() const { return extents_[0]; }
max_size() const159   size_type max_size() const { return num_elements(); }
empty() const160   bool empty() const { return size() == 0; }
num_dimensions() const161   size_type num_dimensions() const { return NumDims; }
shape() const162   const size_type*  shape() const { return extents_; }
strides() const163   const index* strides() const { return strides_; }
index_bases() const164   const index* index_bases() const { return index_base_; }
165 
num_elements() const166   size_type num_elements() const {
167     return std::accumulate(shape(),shape() + num_dimensions(),
168                            size_type(1), std::multiplies<size_type>());
169   }
170 
171 
172 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
173 protected:
174   template <typename,std::size_t> friend class value_accessor_n;
175   template <typename,std::size_t,typename> friend class const_sub_array;
176 #else
177 public:  // Should be protected
178 #endif
179 
const_sub_array(TPtr base,const size_type * extents,const index * strides,const index * index_base)180   const_sub_array (TPtr base,
181                  const size_type* extents,
182                  const index* strides,
183                  const index* index_base) :
184     base_(base), extents_(extents), strides_(strides),
185     index_base_(index_base) {
186   }
187 
188   TPtr base_;
189   const size_type* extents_;
190   const index* strides_;
191   const index* index_base_;
192 private:
193   // const_sub_array cannot be assigned to (no deep copies!)
194   const_sub_array& operator=(const const_sub_array&);
195 };
196 
197 
198 //
199 // sub_array
200 //    multi_array's proxy class to allow multiple overloads of
201 //    operator[] in order to provide a clean multi-dimensional array
202 //    interface.
203 template <typename T, std::size_t NumDims>
204 class sub_array : public const_sub_array<T,NumDims,T*>
205 {
206   typedef const_sub_array<T,NumDims,T*> super_type;
207 public:
208   typedef typename super_type::element element;
209   typedef typename super_type::reference reference;
210   typedef typename super_type::index index;
211   typedef typename super_type::size_type size_type;
212   typedef typename super_type::iterator iterator;
213   typedef typename super_type::reverse_iterator reverse_iterator;
214   typedef typename super_type::const_reference const_reference;
215   typedef typename super_type::const_iterator const_iterator;
216   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
217 
218   // template typedefs
219   template <std::size_t NDims>
220   struct const_array_view {
221     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
222   };
223 
224   template <std::size_t NDims>
225   struct array_view {
226     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
227   };
228 
229   // Assignment from other ConstMultiArray types.
230   template <typename ConstMultiArray>
operator =(const ConstMultiArray & other)231   sub_array& operator=(const ConstMultiArray& other) {
232     function_requires< boost::detail::multi_array::ConstMultiArrayConcept<
233         ConstMultiArray, NumDims> >();
234 
235     // make sure the dimensions agree
236     assert(other.num_dimensions() == this->num_dimensions());
237     assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
238                       this->shape()));
239     // iterator-based copy
240     std::copy(other.begin(),other.end(),begin());
241     return *this;
242   }
243 
244 
operator =(const sub_array & other)245   sub_array& operator=(const sub_array& other) {
246     if (&other != this) {
247       // make sure the dimensions agree
248       assert(other.num_dimensions() == this->num_dimensions());
249       assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
250                         this->shape()));
251       // iterator-based copy
252       std::copy(other.begin(),other.end(),begin());
253     }
254     return *this;
255   }
256 
origin()257   T* origin() { return this->base_; }
origin() const258   const T* origin() const { return this->base_; }
259 
operator [](index idx)260   reference operator[](index idx) {
261     return super_type::access(boost::type<reference>(),
262                               idx,this->base_,this->shape(),this->strides(),
263                               this->index_bases());
264   }
265 
266   // see generate_array_view in base.hpp
267 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
268   template <int NDims>
269 #else
270   template <int NumDims, int NDims> // else ICE
271 #endif // BOOST_MSVC
272   typename array_view<NDims>::type
operator [](const boost::detail::multi_array::index_gen<NumDims,NDims> & indices)273   operator[](const boost::detail::multi_array::
274              index_gen<NumDims,NDims>& indices) {
275     typedef typename array_view<NDims>::type return_type;
276     return
277       super_type::generate_array_view(boost::type<return_type>(),
278                                       indices,
279                                       this->shape(),
280                                       this->strides(),
281                                       this->index_bases(),
282                                       origin());
283   }
284 
285   template <class IndexList>
operator ()(const IndexList & indices)286   element& operator()(const IndexList& indices) {
287     return super_type::access_element(boost::type<element&>(),
288                                       origin(),
289                                       indices,this->strides());
290   }
291 
begin()292   iterator begin() {
293     return iterator(*this->index_bases(),origin(),
294                     this->shape(),this->strides(),this->index_bases());
295   }
296 
end()297   iterator end() {
298     return iterator(*this->index_bases()+(index)*this->shape(),origin(),
299                     this->shape(),this->strides(),this->index_bases());
300   }
301 
302   // RG - rbegin() and rend() written naively to thwart MSVC ICE.
rbegin()303   reverse_iterator rbegin() {
304     reverse_iterator ri(end());
305     return ri;
306   }
307 
rend()308   reverse_iterator rend() {
309     reverse_iterator ri(begin());
310     return ri;
311   }
312 
313   //
314   // proxies
315   //
316 
317   template <class IndexList>
operator ()(const IndexList & indices) const318   const element& operator()(const IndexList& indices) const {
319     return super_type::operator()(indices);
320   }
321 
operator [](index idx) const322   const_reference operator[](index idx) const {
323     return super_type::operator[](idx);
324   }
325 
326   // see generate_array_view in base.hpp
327 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
328   template <int NDims>
329 #else
330   template <int NumDims, int NDims> // else ICE
331 #endif // BOOST_MSVC
332   typename const_array_view<NDims>::type
operator [](const boost::detail::multi_array::index_gen<NumDims,NDims> & indices) const333   operator[](const boost::detail::multi_array::
334              index_gen<NumDims,NDims>& indices)
335     const {
336     return super_type::operator[](indices);
337   }
338 
begin() const339   const_iterator begin() const {
340     return super_type::begin();
341   }
342 
end() const343   const_iterator end() const {
344     return super_type::end();
345   }
346 
rbegin() const347   const_reverse_iterator rbegin() const {
348     return super_type::rbegin();
349   }
350 
rend() const351   const_reverse_iterator rend() const {
352     return super_type::rend();
353   }
354 
355 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
356 private:
357   template <typename,std::size_t> friend class value_accessor_n;
358 #else
359 public: // should be private
360 #endif
361 
sub_array(T * base,const size_type * extents,const index * strides,const index * index_base)362   sub_array (T* base,
363             const size_type* extents,
364             const index* strides,
365             const index* index_base) :
366     super_type(base,extents,strides,index_base) {
367   }
368 
369 };
370 
371 } // namespace multi_array
372 } // namespace detail
373 //
374 // traits classes to get sub_array types
375 //
376 template <typename Array, int N>
377 class subarray_gen {
378   typedef typename Array::element element;
379 public:
380   typedef boost::detail::multi_array::sub_array<element,N> type;
381 };
382 
383 template <typename Array, int N>
384 class const_subarray_gen {
385   typedef typename Array::element element;
386 public:
387   typedef boost::detail::multi_array::const_sub_array<element,N> type;
388 };
389 } // namespace boost
390 
391 #endif // SUBARRAY_RG071801_HPP
392