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_MULTI_ARRAY_REF_RG071801_HPP
14 #define BOOST_MULTI_ARRAY_REF_RG071801_HPP
15 
16 //
17 // multi_array_ref.hpp - code for creating "views" of array data.
18 //
19 
20 #include "boost/multi_array/base.hpp"
21 #include "boost/multi_array/collection_concept.hpp"
22 #include "boost/multi_array/concept_checks.hpp"
23 #include "boost/multi_array/iterator.hpp"
24 #include "boost/multi_array/storage_order.hpp"
25 #include "boost/multi_array/subarray.hpp"
26 #include "boost/multi_array/view.hpp"
27 #include "boost/multi_array/algorithm.hpp"
28 #include "boost/type_traits/is_integral.hpp"
29 #include "boost/utility/enable_if.hpp"
30 #include "boost/array.hpp"
31 #include "boost/concept_check.hpp"
32 #include "boost/functional.hpp"
33 #include "boost/limits.hpp"
34 #include <algorithm>
35 #include <cstddef>
36 #include <functional>
37 #include <numeric>
38 
39 namespace boost {
40 
41 template <typename T, std::size_t NumDims,
42   typename TPtr = const T*
43 >
44 class const_multi_array_ref :
45     public detail::multi_array::multi_array_impl_base<T,NumDims>
46 {
47   typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
48 public:
49   typedef typename super_type::value_type value_type;
50   typedef typename super_type::const_reference const_reference;
51   typedef typename super_type::const_iterator const_iterator;
52   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
53   typedef typename super_type::element element;
54   typedef typename super_type::size_type size_type;
55   typedef typename super_type::difference_type difference_type;
56   typedef typename super_type::index index;
57   typedef typename super_type::extent_range extent_range;
58   typedef general_storage_order<NumDims> storage_order_type;
59 
60   // template typedefs
61   template <std::size_t NDims>
62   struct const_array_view {
63     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
64   };
65 
66   template <std::size_t NDims>
67   struct array_view {
68     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
69   };
70 
71 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
72   // make const_multi_array_ref a friend of itself
73   template <typename,std::size_t,typename>
74   friend class const_multi_array_ref;
75 #endif
76 
77   // This ensures that const_multi_array_ref types with different TPtr
78   // types can convert to each other
79   template <typename OPtr>
const_multi_array_ref(const const_multi_array_ref<T,NumDims,OPtr> & other)80   const_multi_array_ref(const const_multi_array_ref<T,NumDims,OPtr>& other)
81     : base_(other.base_), storage_(other.storage_),
82       extent_list_(other.extent_list_),
83       stride_list_(other.stride_list_),
84       index_base_list_(other.index_base_list_),
85       origin_offset_(other.origin_offset_),
86       directional_offset_(other.directional_offset_),
87       num_elements_(other.num_elements_)  {  }
88 
89   template <typename ExtentList>
const_multi_array_ref(TPtr base,const ExtentList & extents)90   explicit const_multi_array_ref(TPtr base, const ExtentList& extents) :
91     base_(base), storage_(c_storage_order()) {
92     boost::function_requires<
93       CollectionConcept<ExtentList> >();
94 
95     index_base_list_.assign(0);
96     init_multi_array_ref(extents.begin());
97   }
98 
99   template <typename ExtentList>
const_multi_array_ref(TPtr base,const ExtentList & extents,const general_storage_order<NumDims> & so)100   explicit const_multi_array_ref(TPtr base, const ExtentList& extents,
101                        const general_storage_order<NumDims>& so) :
102     base_(base), storage_(so) {
103     boost::function_requires<
104       CollectionConcept<ExtentList> >();
105 
106     index_base_list_.assign(0);
107     init_multi_array_ref(extents.begin());
108   }
109 
const_multi_array_ref(TPtr base,const detail::multi_array::extent_gen<NumDims> & ranges)110   explicit const_multi_array_ref(TPtr base,
111                          const detail::multi_array::
112                          extent_gen<NumDims>& ranges) :
113     base_(base), storage_(c_storage_order()) {
114 
115     init_from_extent_gen(ranges);
116   }
117 
const_multi_array_ref(TPtr base,const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so)118   explicit const_multi_array_ref(TPtr base,
119                            const detail::multi_array::
120                            extent_gen<NumDims>& ranges,
121                            const general_storage_order<NumDims>& so) :
122     base_(base), storage_(so) {
123 
124     init_from_extent_gen(ranges);
125   }
126 
127   template <class InputIterator>
assign(InputIterator begin,InputIterator end)128   void assign(InputIterator begin, InputIterator end) {
129     boost::function_requires<InputIteratorConcept<InputIterator> >();
130 
131     InputIterator in_iter = begin;
132     T* out_iter = base_;
133     std::size_t copy_count=0;
134     while (in_iter != end && copy_count < num_elements_) {
135       *out_iter++ = *in_iter++;
136       copy_count++;
137     }
138   }
139 
140   template <class BaseList>
141 #ifdef BOOST_NO_SFINAE
142   void
143 #else
144   typename
145   disable_if<typename boost::is_integral<BaseList>::type,void >::type
146 #endif // BOOST_NO_SFINAE
reindex(const BaseList & values)147   reindex(const BaseList& values) {
148     boost::function_requires<
149       CollectionConcept<BaseList> >();
150     boost::detail::multi_array::
151       copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
152     origin_offset_ =
153       this->calculate_origin_offset(stride_list_,extent_list_,
154                               storage_,index_base_list_);
155   }
156 
reindex(index value)157   void reindex(index value) {
158     index_base_list_.assign(value);
159     origin_offset_ =
160       this->calculate_origin_offset(stride_list_,extent_list_,
161                               storage_,index_base_list_);
162   }
163 
164   template <typename SizeList>
reshape(const SizeList & extents)165   void reshape(const SizeList& extents) {
166     boost::function_requires<
167       CollectionConcept<SizeList> >();
168     BOOST_ASSERT(num_elements_ ==
169                  std::accumulate(extents.begin(),extents.end(),
170                                  size_type(1),std::multiplies<size_type>()));
171 
172     std::copy(extents.begin(),extents.end(),extent_list_.begin());
173     this->compute_strides(stride_list_,extent_list_,storage_);
174 
175     origin_offset_ =
176       this->calculate_origin_offset(stride_list_,extent_list_,
177                               storage_,index_base_list_);
178   }
179 
num_dimensions() const180   size_type num_dimensions() const { return NumDims; }
181 
size() const182   size_type size() const { return extent_list_.front(); }
183 
184   // given reshaping functionality, this is the max possible size.
max_size() const185   size_type max_size() const { return num_elements(); }
186 
empty() const187   bool empty() const { return size() == 0; }
188 
shape() const189   const size_type* shape() const {
190     return extent_list_.data();
191   }
192 
strides() const193   const index* strides() const {
194     return stride_list_.data();
195   }
196 
origin() const197   const element* origin() const { return base_+origin_offset_; }
data() const198   const element* data() const { return base_; }
199 
num_elements() const200   size_type num_elements() const { return num_elements_; }
201 
index_bases() const202   const index* index_bases() const {
203     return index_base_list_.data();
204   }
205 
206 
storage_order() const207   const storage_order_type& storage_order() const {
208     return storage_;
209   }
210 
211   template <typename IndexList>
operator ()(IndexList indices) const212   const element& operator()(IndexList indices) const {
213     boost::function_requires<
214       CollectionConcept<IndexList> >();
215     return super_type::access_element(boost::type<const element&>(),
216                                       indices,origin(),
217                                       shape(),strides(),index_bases());
218   }
219 
220   // Only allow const element access
operator [](index idx) const221   const_reference operator[](index idx) const {
222     return super_type::access(boost::type<const_reference>(),
223                               idx,origin(),
224                               shape(),strides(),index_bases());
225   }
226 
227   // see generate_array_view in base.hpp
228   template <int NDims>
229   typename const_array_view<NDims>::type
operator [](const detail::multi_array::index_gen<NumDims,NDims> & indices) const230   operator[](const detail::multi_array::
231              index_gen<NumDims,NDims>& indices)
232     const {
233     typedef typename const_array_view<NDims>::type return_type;
234     return
235       super_type::generate_array_view(boost::type<return_type>(),
236                                       indices,
237                                       shape(),
238                                       strides(),
239                                       index_bases(),
240                                       origin());
241   }
242 
begin() const243   const_iterator begin() const {
244     return const_iterator(*index_bases(),origin(),
245                           shape(),strides(),index_bases());
246   }
247 
end() const248   const_iterator end() const {
249     return const_iterator(*index_bases()+(index)*shape(),origin(),
250                           shape(),strides(),index_bases());
251   }
252 
rbegin() const253   const_reverse_iterator rbegin() const {
254     return const_reverse_iterator(end());
255   }
256 
rend() const257   const_reverse_iterator rend() const {
258     return const_reverse_iterator(begin());
259   }
260 
261 
262   template <typename OPtr>
operator ==(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const263   bool operator==(const
264                   const_multi_array_ref<T,NumDims,OPtr>& rhs)
265     const {
266     if(std::equal(extent_list_.begin(),
267                   extent_list_.end(),
268                   rhs.extent_list_.begin()))
269       return std::equal(begin(),end(),rhs.begin());
270     else return false;
271   }
272 
273   template <typename OPtr>
operator <(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const274   bool operator<(const
275                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
276     const {
277     return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
278   }
279 
280   template <typename OPtr>
operator !=(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const281   bool operator!=(const
282                   const_multi_array_ref<T,NumDims,OPtr>& rhs)
283     const {
284     return !(*this == rhs);
285   }
286 
287   template <typename OPtr>
operator >(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const288   bool operator>(const
289                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
290     const {
291     return rhs < *this;
292   }
293 
294   template <typename OPtr>
operator <=(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const295   bool operator<=(const
296                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
297     const {
298     return !(*this > rhs);
299   }
300 
301   template <typename OPtr>
operator >=(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const302   bool operator>=(const
303                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
304     const {
305     return !(*this < rhs);
306   }
307 
308 
309 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
310 protected:
311 #else
312 public:
313 #endif
314 
315   typedef boost::array<size_type,NumDims> size_list;
316   typedef boost::array<index,NumDims> index_list;
317 
318   // This is used by multi_array, which is a subclass of this
set_base_ptr(TPtr new_base)319   void set_base_ptr(TPtr new_base) { base_ = new_base; }
320 
321 
322   // This constructor supports multi_array's default constructor
323   // and constructors from multi_array_ref, subarray, and array_view
324   explicit
const_multi_array_ref(TPtr base,const storage_order_type & so,const index * index_bases,const size_type * extents)325   const_multi_array_ref(TPtr base,
326                         const storage_order_type& so,
327                         const index * index_bases,
328                         const size_type* extents) :
329     base_(base), storage_(so), origin_offset_(0), directional_offset_(0)
330  {
331    // If index_bases or extents is null, then initialize the corresponding
332    // private data to zeroed lists.
333    if(index_bases) {
334      boost::detail::multi_array::
335        copy_n(index_bases,NumDims,index_base_list_.begin());
336    } else {
337      std::fill_n(index_base_list_.begin(),NumDims,0);
338    }
339    if(extents) {
340      init_multi_array_ref(extents);
341    } else {
342      boost::array<index,NumDims> extent_list;
343      extent_list.assign(0);
344      init_multi_array_ref(extent_list.begin());
345    }
346  }
347 
348 
349   TPtr base_;
350   storage_order_type storage_;
351   size_list extent_list_;
352   index_list stride_list_;
353   index_list index_base_list_;
354   index origin_offset_;
355   index directional_offset_;
356   size_type num_elements_;
357 
358 private:
359   // const_multi_array_ref cannot be assigned to (no deep copies!)
360   const_multi_array_ref& operator=(const const_multi_array_ref& other);
361 
init_from_extent_gen(const detail::multi_array::extent_gen<NumDims> & ranges)362   void init_from_extent_gen(const
363                         detail::multi_array::
364                         extent_gen<NumDims>& ranges) {
365 
366     typedef boost::array<index,NumDims> extent_list;
367 
368     // get the index_base values
369     std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
370               index_base_list_.begin(),
371               boost::mem_fun_ref(&extent_range::start));
372 
373     // calculate the extents
374     extent_list extents;
375     std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
376               extents.begin(),
377               boost::mem_fun_ref(&extent_range::size));
378 
379     init_multi_array_ref(extents.begin());
380   }
381 
382 
383 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
384 protected:
385 #else
386 public:
387 #endif
388   // RG - move me!
389   template <class InputIterator>
init_multi_array_ref(InputIterator extents_iter)390   void init_multi_array_ref(InputIterator extents_iter) {
391     boost::function_requires<InputIteratorConcept<InputIterator> >();
392 
393     boost::detail::multi_array::
394       copy_n(extents_iter,num_dimensions(),extent_list_.begin());
395 
396     // Calculate the array size
397     num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
398                             size_type(1),std::multiplies<size_type>());
399 
400     this->compute_strides(stride_list_,extent_list_,storage_);
401 
402     origin_offset_ =
403       this->calculate_origin_offset(stride_list_,extent_list_,
404                               storage_,index_base_list_);
405     directional_offset_ =
406       this->calculate_descending_dimension_offset(stride_list_,extent_list_,
407                                             storage_);
408   }
409 };
410 
411 template <typename T, std::size_t NumDims>
412 class multi_array_ref :
413   public const_multi_array_ref<T,NumDims,T*>
414 {
415   typedef const_multi_array_ref<T,NumDims,T*> super_type;
416 public:
417   typedef typename super_type::value_type value_type;
418   typedef typename super_type::reference reference;
419   typedef typename super_type::iterator iterator;
420   typedef typename super_type::reverse_iterator reverse_iterator;
421   typedef typename super_type::const_reference const_reference;
422   typedef typename super_type::const_iterator const_iterator;
423   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
424   typedef typename super_type::element element;
425   typedef typename super_type::size_type size_type;
426   typedef typename super_type::difference_type difference_type;
427   typedef typename super_type::index index;
428   typedef typename super_type::extent_range extent_range;
429 
430   typedef typename super_type::storage_order_type storage_order_type;
431   typedef typename super_type::index_list index_list;
432   typedef typename super_type::size_list size_list;
433 
434   template <std::size_t NDims>
435   struct const_array_view {
436     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
437   };
438 
439   template <std::size_t NDims>
440   struct array_view {
441     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
442   };
443 
444   template <class ExtentList>
multi_array_ref(T * base,const ExtentList & extents)445   explicit multi_array_ref(T* base, const ExtentList& extents) :
446     super_type(base,extents) {
447     boost::function_requires<
448       CollectionConcept<ExtentList> >();
449   }
450 
451   template <class ExtentList>
multi_array_ref(T * base,const ExtentList & extents,const general_storage_order<NumDims> & so)452   explicit multi_array_ref(T* base, const ExtentList& extents,
453                            const general_storage_order<NumDims>& so) :
454     super_type(base,extents,so) {
455     boost::function_requires<
456       CollectionConcept<ExtentList> >();
457   }
458 
459 
multi_array_ref(T * base,const detail::multi_array::extent_gen<NumDims> & ranges)460   explicit multi_array_ref(T* base,
461                            const detail::multi_array::
462                            extent_gen<NumDims>& ranges) :
463     super_type(base,ranges) { }
464 
465 
multi_array_ref(T * base,const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so)466   explicit multi_array_ref(T* base,
467                            const detail::multi_array::
468                            extent_gen<NumDims>&
469                              ranges,
470                            const general_storage_order<NumDims>& so) :
471     super_type(base,ranges,so) { }
472 
473 
474   // Assignment from other ConstMultiArray types.
475   template <typename ConstMultiArray>
operator =(const ConstMultiArray & other)476   multi_array_ref& operator=(const ConstMultiArray& other) {
477     function_requires<
478       multi_array_concepts::
479       ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
480 
481     // make sure the dimensions agree
482     BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
483     BOOST_ASSERT(std::equal(other.shape(),other.shape()+this->num_dimensions(),
484                             this->shape()));
485     // iterator-based copy
486     std::copy(other.begin(),other.end(),this->begin());
487     return *this;
488   }
489 
operator =(const multi_array_ref & other)490   multi_array_ref& operator=(const multi_array_ref& other) {
491     if (&other != this) {
492       // make sure the dimensions agree
493 
494       BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
495       BOOST_ASSERT(std::equal(other.shape(),
496                               other.shape()+this->num_dimensions(),
497                               this->shape()));
498       // iterator-based copy
499       std::copy(other.begin(),other.end(),this->begin());
500     }
501     return *this;
502   }
503 
origin()504   element* origin() { return super_type::base_+super_type::origin_offset_; }
505 
data()506   element* data() { return super_type::base_; }
507 
508   template <class IndexList>
operator ()(const IndexList & indices)509   element& operator()(const IndexList& indices) {
510     boost::function_requires<
511       CollectionConcept<IndexList> >();
512     return super_type::access_element(boost::type<element&>(),
513                                       indices,origin(),
514                                       this->shape(),this->strides(),
515                                       this->index_bases());
516   }
517 
518 
operator [](index idx)519   reference operator[](index idx) {
520     return super_type::access(boost::type<reference>(),
521                               idx,origin(),
522                               this->shape(),this->strides(),
523                               this->index_bases());
524   }
525 
526 
527   // See note attached to generate_array_view in base.hpp
528   template <int NDims>
529   typename array_view<NDims>::type
operator [](const detail::multi_array::index_gen<NumDims,NDims> & indices)530   operator[](const detail::multi_array::
531              index_gen<NumDims,NDims>& indices) {
532     typedef typename array_view<NDims>::type return_type;
533     return
534       super_type::generate_array_view(boost::type<return_type>(),
535                                       indices,
536                                       this->shape(),
537                                       this->strides(),
538                                       this->index_bases(),
539                                       origin());
540   }
541 
542 
begin()543   iterator begin() {
544     return iterator(*this->index_bases(),origin(),this->shape(),
545                     this->strides(),this->index_bases());
546   }
547 
end()548   iterator end() {
549     return iterator(*this->index_bases()+(index)*this->shape(),origin(),
550                     this->shape(),this->strides(),
551                     this->index_bases());
552   }
553 
554   // rbegin() and rend() written naively to thwart MSVC ICE.
rbegin()555   reverse_iterator rbegin() {
556     reverse_iterator ri(end());
557     return ri;
558   }
559 
rend()560   reverse_iterator rend() {
561     reverse_iterator ri(begin());
562     return ri;
563   }
564 
565   // Using declarations don't seem to work for g++
566   // These are the proxies to work around this.
567 
origin() const568   const element* origin() const { return super_type::origin(); }
data() const569   const element* data() const { return super_type::data(); }
570 
571   template <class IndexList>
operator ()(const IndexList & indices) const572   const element& operator()(const IndexList& indices) const {
573     boost::function_requires<
574       CollectionConcept<IndexList> >();
575     return super_type::operator()(indices);
576   }
577 
operator [](index idx) const578   const_reference operator[](index idx) const {
579     return super_type::access(boost::type<const_reference>(),
580                               idx,origin(),
581                               this->shape(),this->strides(),
582                               this->index_bases());
583   }
584 
585   // See note attached to generate_array_view in base.hpp
586   template <int NDims>
587   typename const_array_view<NDims>::type
operator [](const detail::multi_array::index_gen<NumDims,NDims> & indices) const588   operator[](const detail::multi_array::
589              index_gen<NumDims,NDims>& indices)
590     const {
591     return super_type::operator[](indices);
592   }
593 
begin() const594   const_iterator begin() const {
595     return super_type::begin();
596   }
597 
end() const598   const_iterator end() const {
599     return super_type::end();
600   }
601 
rbegin() const602   const_reverse_iterator rbegin() const {
603     return super_type::rbegin();
604   }
605 
rend() const606   const_reverse_iterator rend() const {
607     return super_type::rend();
608   }
609 
610 protected:
611   // This is only supplied to support multi_array's default constructor
multi_array_ref(T * base,const storage_order_type & so,const index * index_bases,const size_type * extents)612   explicit multi_array_ref(T* base,
613                            const storage_order_type& so,
614                            const index* index_bases,
615                            const size_type* extents) :
616     super_type(base,so,index_bases,extents) { }
617 
618 };
619 
620 } // namespace boost
621 
622 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP
623