1 // Copyright 2002 The Trustees of Indiana University.
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)
7 // Boost.MultiArray Library
8 // Authors: Ronald Garcia
11 // See http://www.boost.org/libs/multi_array for documentation.
13 #ifndef BOOST_MULTI_ARRAY_REF_RG071801_HPP
14 #define BOOST_MULTI_ARRAY_REF_RG071801_HPP
17 // multi_array_ref.hpp - code for creating "views" of array data.
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"
40 template <typename T, std::size_t NumDims,
41 typename TPtr = const T*
43 class const_multi_array_ref :
44 public detail::multi_array::multi_array_impl_base<T,NumDims>
46 typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
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;
60 template <std::size_t NDims>
61 struct const_array_view {
62 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
65 template <std::size_t NDims>
67 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
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;
75 // template <typename From, typename To> // needed for enable_if_convertible tests
76 // friend class boost::detail::is_convertible_basic_impl;
79 template <typename OPtr>
80 const_multi_array_ref(const const_multi_array_ref<T,NumDims,
82 : base_(other.base_), storage_(other.storage_),
83 extent_list_(other.extent_list_),
84 stride_list_(other.stride_list_),
85 index_base_list_(other.index_base_list_),
86 origin_offset_(other.origin_offset_),
87 directional_offset_(other.directional_offset_),
88 num_elements_(other.num_elements_) { }
90 template <typename ExtentList>
91 explicit const_multi_array_ref(TPtr base, const ExtentList& extents) :
92 base_(base), storage_(c_storage_order()) {
93 boost::function_requires<
94 detail::multi_array::CollectionConcept<ExtentList> >();
96 index_base_list_.assign(0);
97 init_multi_array_ref(extents.begin());
100 template <typename ExtentList>
101 explicit const_multi_array_ref(TPtr base, const ExtentList& extents,
102 const general_storage_order<NumDims>& so) :
103 base_(base), storage_(so) {
104 boost::function_requires<
105 detail::multi_array::CollectionConcept<ExtentList> >();
107 index_base_list_.assign(0);
108 init_multi_array_ref(extents.begin());
111 explicit const_multi_array_ref(TPtr base,
112 const detail::multi_array::
113 extent_gen<NumDims>& ranges) :
114 base_(base), storage_(c_storage_order()) {
116 init_from_extent_gen(ranges);
119 explicit const_multi_array_ref(TPtr base,
120 const detail::multi_array::
121 extent_gen<NumDims>& ranges,
122 const general_storage_order<NumDims>& so) :
123 base_(base), storage_(so) {
125 init_from_extent_gen(ranges);
128 template <class InputIterator>
129 void assign(InputIterator begin, InputIterator end) {
130 boost::function_requires<InputIteratorConcept<InputIterator> >();
132 InputIterator in_iter = begin;
134 std::size_t copy_count=0;
135 while (in_iter != end && copy_count < num_elements_) {
136 *out_iter++ = *in_iter++;
141 template <class BaseList>
142 void reindex(const BaseList& values) {
143 boost::function_requires<
144 detail::multi_array::CollectionConcept<BaseList> >();
145 boost::copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
147 this->calculate_origin_offset(stride_list_,extent_list_,
148 storage_,index_base_list_);
151 void reindex(index value) {
152 index_base_list_.assign(value);
154 this->calculate_origin_offset(stride_list_,extent_list_,
155 storage_,index_base_list_);
158 template <typename SizeList>
159 void reshape(const SizeList& extents) {
160 boost::function_requires<
161 detail::multi_array::CollectionConcept<SizeList> >();
162 assert(num_elements_ ==
163 std::accumulate(extents.begin(),extents.end(),
164 size_type(1),std::multiplies<size_type>()));
166 std::copy(extents.begin(),extents.end(),extent_list_.begin());
167 this->compute_strides(stride_list_,extent_list_,storage_);
170 this->calculate_origin_offset(stride_list_,extent_list_,
171 storage_,index_base_list_);
174 size_type num_dimensions() const { return NumDims; }
176 size_type size() const { return extent_list_.front(); }
178 // given reshaping functionality, this is the max possible size.
179 size_type max_size() const { return num_elements(); }
181 bool empty() const { return size() == 0; }
183 const size_type* shape() const {
184 return extent_list_.data();
187 const index* strides() const {
188 return stride_list_.data();
191 const element* origin() const { return base_+origin_offset_; }
192 const element* data() const { return base_; }
194 size_type num_elements() const { return num_elements_; }
196 const index* index_bases() const {
197 return index_base_list_.data();
201 const storage_order_type& storage_order() const {
205 template <typename IndexList>
206 const element& operator()(IndexList indices) const {
207 boost::function_requires<
208 detail::multi_array::CollectionConcept<IndexList> >();
209 return super_type::access_element(boost::type<const element&>(),
214 // Only allow const element access
215 const_reference operator[](index idx) const {
216 return super_type::access(boost::type<const_reference>(),
218 shape(),strides(),index_bases());
221 // see generate_array_view in base.hpp
222 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
225 template <int NumDims, int NDims> // else ICE
227 typename const_array_view<NDims>::type
228 operator[](const detail::multi_array::
229 index_gen<NumDims,NDims>& indices)
231 typedef typename const_array_view<NDims>::type return_type;
233 super_type::generate_array_view(boost::type<return_type>(),
241 const_iterator begin() const {
242 return const_iterator(*index_bases(),origin(),
243 shape(),strides(),index_bases());
246 const_iterator end() const {
247 return const_iterator(*index_bases()+*shape(),origin(),
248 shape(),strides(),index_bases());
251 const_reverse_iterator rbegin() const {
252 return const_reverse_iterator(end());
255 const_reverse_iterator rend() const {
256 return const_reverse_iterator(begin());
260 template <typename OPtr>
261 bool operator==(const
262 const_multi_array_ref<T,NumDims,OPtr>& rhs)
264 if(std::equal(extent_list_.begin(),
266 rhs.extent_list_.begin()))
267 return std::equal(begin(),end(),rhs.begin());
271 template <typename OPtr>
273 const_multi_array_ref<T,NumDims,OPtr>& rhs)
275 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
278 template <typename OPtr>
279 bool operator!=(const
280 const_multi_array_ref<T,NumDims,OPtr>& rhs)
282 return !(*this == rhs);
285 template <typename OPtr>
287 const_multi_array_ref<T,NumDims,OPtr>& rhs)
292 template <typename OPtr>
293 bool operator<=(const
294 const_multi_array_ref<T,NumDims,OPtr>& rhs)
296 return !(*this > rhs);
299 template <typename OPtr>
300 bool operator>=(const
301 const_multi_array_ref<T,NumDims,OPtr>& rhs)
303 return !(*this < rhs);
307 // This is only supplied to support multi_array's default constructor
308 explicit const_multi_array_ref(TPtr base) :
309 base_(base), storage_(c_storage_order()) {
310 index_base_list_.assign(0);
311 boost::array<size_type,NumDims> filler;
313 init_multi_array_ref(filler.begin());
317 // This ensures that const_multi_array_ref types with different TPtr
318 // types can convert to each other
319 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
324 // This is used by multi_array, which is a subclass of this
325 void set_base_ptr(TPtr new_base) { base_ = new_base; }
327 template <typename OPtr>
328 const_multi_array_ref(
329 const detail::multi_array::const_sub_array<T,NumDims,OPtr>& rhs
331 : base_(0), // playing it "safe"; so we learn of errors
332 storage_(c_storage_order()),
333 origin_offset_(0), directional_offset_(0),
334 num_elements_(rhs.num_elements())
337 copy_n(rhs.shape(),rhs.num_dimensions(),extent_list_.begin());
338 copy_n(rhs.strides(),rhs.num_dimensions(),stride_list_.begin());
339 copy_n(rhs.index_bases(),rhs.num_dimensions(),index_base_list_.begin());
342 typedef boost::array<size_type,NumDims> size_list;
343 typedef boost::array<index,NumDims> index_list;
346 storage_order_type storage_;
347 size_list extent_list_;
348 index_list stride_list_;
349 index_list index_base_list_;
350 index origin_offset_;
351 index directional_offset_;
352 size_type num_elements_;
355 // const_multi_array_ref cannot be assigned to (no deep copies!)
356 const_multi_array_ref& operator=(const const_multi_array_ref& other);
358 void init_from_extent_gen(const
359 detail::multi_array::
360 extent_gen<NumDims>& ranges) {
362 typedef boost::array<index,NumDims> extent_list;
364 // get the index_base values
365 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
366 index_base_list_.begin(),
367 boost::mem_fun_ref(&extent_range::start));
369 // calculate the extents
371 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
373 boost::mem_fun_ref(&extent_range::size));
375 init_multi_array_ref(extents.begin());
379 template <class InputIterator>
380 void init_multi_array_ref(InputIterator extents_iter) {
381 boost::function_requires<InputIteratorConcept<InputIterator> >();
383 boost::copy_n(extents_iter,num_dimensions(),extent_list_.begin());
385 // Calculate the array size
386 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
387 1,std::multiplies<index>());
389 assert(num_elements_ != 0);
391 this->compute_strides(stride_list_,extent_list_,storage_);
394 this->calculate_origin_offset(stride_list_,extent_list_,
395 storage_,index_base_list_);
396 directional_offset_ =
397 this->calculate_descending_dimension_offset(stride_list_,extent_list_,
402 template <typename T, std::size_t NumDims>
403 class multi_array_ref :
404 public const_multi_array_ref<T,NumDims,T*>
406 typedef const_multi_array_ref<T,NumDims,T*> super_type;
408 typedef typename super_type::value_type value_type;
409 typedef typename super_type::reference reference;
410 typedef typename super_type::iterator iterator;
411 typedef typename super_type::reverse_iterator reverse_iterator;
412 typedef typename super_type::const_reference const_reference;
413 typedef typename super_type::const_iterator const_iterator;
414 typedef typename super_type::const_reverse_iterator const_reverse_iterator;
415 typedef typename super_type::element element;
416 typedef typename super_type::size_type size_type;
417 typedef typename super_type::difference_type difference_type;
418 typedef typename super_type::index index;
419 typedef typename super_type::extent_range extent_range;
423 template <std::size_t NDims>
424 struct const_array_view {
425 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
428 template <std::size_t NDims>
430 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
433 template <class ExtentList>
434 explicit multi_array_ref(T* base, const ExtentList& extents) :
435 super_type(base,extents) {
436 boost::function_requires<
437 detail::multi_array::CollectionConcept<ExtentList> >();
440 template <class ExtentList>
441 explicit multi_array_ref(T* base, const ExtentList& extents,
442 const general_storage_order<NumDims>& so) :
443 super_type(base,extents,so) {
444 boost::function_requires<
445 detail::multi_array::CollectionConcept<ExtentList> >();
449 explicit multi_array_ref(T* base,
450 const detail::multi_array::
451 extent_gen<NumDims>& ranges) :
452 super_type(base,ranges) { }
455 explicit multi_array_ref(T* base,
456 const detail::multi_array::
459 const general_storage_order<NumDims>& so) :
460 super_type(base,ranges,so) { }
462 template <typename OPtr>
463 multi_array_ref(const detail::multi_array::
464 const_sub_array<T,NumDims,OPtr>& rhs)
467 // Assignment from other ConstMultiArray types.
468 template <typename ConstMultiArray>
469 multi_array_ref& operator=(const ConstMultiArray& other) {
471 detail::multi_array::
472 ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
474 // make sure the dimensions agree
475 assert(other.num_dimensions() == this->num_dimensions());
476 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
478 // iterator-based copy
479 std::copy(other.begin(),other.end(),this->begin());
483 multi_array_ref& operator=(const multi_array_ref& other) {
484 if (&other != this) {
485 // make sure the dimensions agree
487 assert(other.num_dimensions() == this->num_dimensions());
488 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
490 // iterator-based copy
491 std::copy(other.begin(),other.end(),this->begin());
496 element* origin() { return super_type::base_+super_type::origin_offset_; }
498 element* data() { return super_type::base_; }
500 template <class IndexList>
501 element& operator()(const IndexList& indices) {
502 boost::function_requires<
503 detail::multi_array::CollectionConcept<IndexList> >();
504 return super_type::access_element(boost::type<element&>(),
506 indices,this->strides());
510 reference operator[](index idx) {
511 return super_type::access(boost::type<reference>(),
513 this->shape(),this->strides(),
514 this->index_bases());
518 // See note attached to generate_array_view in base.hpp
519 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
522 template <int NumDims, int NDims> // else ICE
524 typename array_view<NDims>::type
525 operator[](const detail::multi_array::
526 index_gen<NumDims,NDims>& indices) {
527 typedef typename array_view<NDims>::type return_type;
529 super_type::generate_array_view(boost::type<return_type>(),
539 return iterator(*this->index_bases(),origin(),this->shape(),
540 this->strides(),this->index_bases());
544 return iterator(*this->index_bases()+*this->shape(),origin(),
545 this->shape(),this->strides(),
546 this->index_bases());
549 // RG - rbegin() and rend() written naively to thwart MSVC ICE.
550 reverse_iterator rbegin() {
551 reverse_iterator ri(end());
555 reverse_iterator rend() {
556 reverse_iterator ri(begin());
560 // Using declarations don't seem to work for g++
561 // These are the proxies to work around this.
563 const element* origin() const { return super_type::origin(); }
564 const element* data() const { return super_type::data(); }
566 template <class IndexList>
567 const element& operator()(const IndexList& indices) const {
568 boost::function_requires<
569 detail::multi_array::CollectionConcept<IndexList> >();
570 return super_type::operator()(indices);
573 const_reference operator[](index idx) const {
574 return super_type::access(boost::type<const_reference>(),
576 this->shape(),this->strides(),
577 this->index_bases());
580 // See note attached to generate_array_view in base.hpp
581 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
584 template <int NumDims, int NDims> // else ICE
586 typename const_array_view<NDims>::type
587 operator[](const detail::multi_array::
588 index_gen<NumDims,NDims>& indices)
590 return super_type::operator[](indices);
593 const_iterator begin() const {
594 return super_type::begin();
597 const_iterator end() const {
598 return super_type::end();
601 const_reverse_iterator rbegin() const {
602 return super_type::rbegin();
605 const_reverse_iterator rend() const {
606 return super_type::rend();
610 // This is only supplied to support multi_array's default constructor
611 explicit multi_array_ref(T* base) :
620 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP