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