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/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"
41 template <typename T, std::size_t NumDims,
42 typename TPtr = const T*
44 class const_multi_array_ref :
45 public detail::multi_array::multi_array_impl_base<T,NumDims>
47 typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
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;
61 template <std::size_t NDims>
62 struct const_array_view {
63 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
66 template <std::size_t NDims>
68 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
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;
77 // This ensures that const_multi_array_ref types with different TPtr
78 // types can convert to each other
79 template <typename OPtr>
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_) { }
89 template <typename ExtentList>
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> >();
95 index_base_list_.assign(0);
96 init_multi_array_ref(extents.begin());
99 template <typename ExtentList>
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> >();
106 index_base_list_.assign(0);
107 init_multi_array_ref(extents.begin());
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()) {
115 init_from_extent_gen(ranges);
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) {
124 init_from_extent_gen(ranges);
127 template <class InputIterator>
128 void assign(InputIterator begin, InputIterator end) {
129 boost::function_requires<InputIteratorConcept<InputIterator> >();
131 InputIterator in_iter = begin;
133 std::size_t copy_count=0;
134 while (in_iter != end && copy_count < num_elements_) {
135 *out_iter++ = *in_iter++;
140 template <class BaseList>
141 #ifdef BOOST_NO_SFINAE
145 disable_if<typename boost::is_integral<BaseList>::type,void >::type
146 #endif // BOOST_NO_SFINAE
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());
153 this->calculate_origin_offset(stride_list_,extent_list_,
154 storage_,index_base_list_);
157 void reindex(index value) {
158 index_base_list_.assign(value);
160 this->calculate_origin_offset(stride_list_,extent_list_,
161 storage_,index_base_list_);
164 template <typename SizeList>
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>()));
172 std::copy(extents.begin(),extents.end(),extent_list_.begin());
173 this->compute_strides(stride_list_,extent_list_,storage_);
176 this->calculate_origin_offset(stride_list_,extent_list_,
177 storage_,index_base_list_);
180 size_type num_dimensions() const { return NumDims; }
182 size_type size() const { return extent_list_.front(); }
184 // given reshaping functionality, this is the max possible size.
185 size_type max_size() const { return num_elements(); }
187 bool empty() const { return size() == 0; }
189 const size_type* shape() const {
190 return extent_list_.data();
193 const index* strides() const {
194 return stride_list_.data();
197 const element* origin() const { return base_+origin_offset_; }
198 const element* data() const { return base_; }
200 size_type num_elements() const { return num_elements_; }
202 const index* index_bases() const {
203 return index_base_list_.data();
207 const storage_order_type& storage_order() const {
211 template <typename IndexList>
212 const element& operator()(IndexList indices) const {
213 boost::function_requires<
214 CollectionConcept<IndexList> >();
215 return super_type::access_element(boost::type<const element&>(),
217 shape(),strides(),index_bases());
220 // Only allow const element access
221 const_reference operator[](index idx) const {
222 return super_type::access(boost::type<const_reference>(),
224 shape(),strides(),index_bases());
227 // see generate_array_view in base.hpp
229 typename const_array_view<NDims>::type
230 operator[](const detail::multi_array::
231 index_gen<NumDims,NDims>& indices)
233 typedef typename const_array_view<NDims>::type return_type;
235 super_type::generate_array_view(boost::type<return_type>(),
243 const_iterator begin() const {
244 return const_iterator(*index_bases(),origin(),
245 shape(),strides(),index_bases());
248 const_iterator end() const {
249 return const_iterator(*index_bases()+(index)*shape(),origin(),
250 shape(),strides(),index_bases());
253 const_reverse_iterator rbegin() const {
254 return const_reverse_iterator(end());
257 const_reverse_iterator rend() const {
258 return const_reverse_iterator(begin());
262 template <typename OPtr>
263 bool operator==(const
264 const_multi_array_ref<T,NumDims,OPtr>& rhs)
266 if(std::equal(extent_list_.begin(),
268 rhs.extent_list_.begin()))
269 return std::equal(begin(),end(),rhs.begin());
273 template <typename OPtr>
275 const_multi_array_ref<T,NumDims,OPtr>& rhs)
277 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
280 template <typename OPtr>
281 bool operator!=(const
282 const_multi_array_ref<T,NumDims,OPtr>& rhs)
284 return !(*this == rhs);
287 template <typename OPtr>
289 const_multi_array_ref<T,NumDims,OPtr>& rhs)
294 template <typename OPtr>
295 bool operator<=(const
296 const_multi_array_ref<T,NumDims,OPtr>& rhs)
298 return !(*this > rhs);
301 template <typename OPtr>
302 bool operator>=(const
303 const_multi_array_ref<T,NumDims,OPtr>& rhs)
305 return !(*this < rhs);
309 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
315 typedef boost::array<size_type,NumDims> size_list;
316 typedef boost::array<index,NumDims> index_list;
318 // This is used by multi_array, which is a subclass of this
319 void set_base_ptr(TPtr new_base) { base_ = new_base; }
322 // This constructor supports multi_array's default constructor
323 // and constructors from multi_array_ref, subarray, and array_view
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)
331 // If index_bases or extents is null, then initialize the corresponding
332 // private data to zeroed lists.
334 boost::detail::multi_array::
335 copy_n(index_bases,NumDims,index_base_list_.begin());
337 std::fill_n(index_base_list_.begin(),NumDims,0);
340 init_multi_array_ref(extents);
342 boost::array<index,NumDims> extent_list;
343 extent_list.assign(0);
344 init_multi_array_ref(extent_list.begin());
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_;
359 // const_multi_array_ref cannot be assigned to (no deep copies!)
360 const_multi_array_ref& operator=(const const_multi_array_ref& other);
362 void init_from_extent_gen(const
363 detail::multi_array::
364 extent_gen<NumDims>& ranges) {
366 typedef boost::array<index,NumDims> extent_list;
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));
373 // calculate the extents
375 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
377 boost::mem_fun_ref(&extent_range::size));
379 init_multi_array_ref(extents.begin());
383 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
389 template <class InputIterator>
390 void init_multi_array_ref(InputIterator extents_iter) {
391 boost::function_requires<InputIteratorConcept<InputIterator> >();
393 boost::detail::multi_array::
394 copy_n(extents_iter,num_dimensions(),extent_list_.begin());
396 // Calculate the array size
397 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
398 size_type(1),std::multiplies<size_type>());
400 this->compute_strides(stride_list_,extent_list_,storage_);
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_,
411 template <typename T, std::size_t NumDims>
412 class multi_array_ref :
413 public const_multi_array_ref<T,NumDims,T*>
415 typedef const_multi_array_ref<T,NumDims,T*> super_type;
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;
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;
434 template <std::size_t NDims>
435 struct const_array_view {
436 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
439 template <std::size_t NDims>
441 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
444 template <class ExtentList>
445 explicit multi_array_ref(T* base, const ExtentList& extents) :
446 super_type(base,extents) {
447 boost::function_requires<
448 CollectionConcept<ExtentList> >();
451 template <class ExtentList>
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> >();
460 explicit multi_array_ref(T* base,
461 const detail::multi_array::
462 extent_gen<NumDims>& ranges) :
463 super_type(base,ranges) { }
466 explicit multi_array_ref(T* base,
467 const detail::multi_array::
470 const general_storage_order<NumDims>& so) :
471 super_type(base,ranges,so) { }
474 // Assignment from other ConstMultiArray types.
475 template <typename ConstMultiArray>
476 multi_array_ref& operator=(const ConstMultiArray& other) {
478 multi_array_concepts::
479 ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
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(),
485 // iterator-based copy
486 std::copy(other.begin(),other.end(),this->begin());
490 multi_array_ref& operator=(const multi_array_ref& other) {
491 if (&other != this) {
492 // make sure the dimensions agree
494 BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
495 BOOST_ASSERT(std::equal(other.shape(),
496 other.shape()+this->num_dimensions(),
498 // iterator-based copy
499 std::copy(other.begin(),other.end(),this->begin());
504 element* origin() { return super_type::base_+super_type::origin_offset_; }
506 element* data() { return super_type::base_; }
508 template <class IndexList>
509 element& operator()(const IndexList& indices) {
510 boost::function_requires<
511 CollectionConcept<IndexList> >();
512 return super_type::access_element(boost::type<element&>(),
514 this->shape(),this->strides(),
515 this->index_bases());
519 reference operator[](index idx) {
520 return super_type::access(boost::type<reference>(),
522 this->shape(),this->strides(),
523 this->index_bases());
527 // See note attached to generate_array_view in base.hpp
529 typename array_view<NDims>::type
530 operator[](const detail::multi_array::
531 index_gen<NumDims,NDims>& indices) {
532 typedef typename array_view<NDims>::type return_type;
534 super_type::generate_array_view(boost::type<return_type>(),
544 return iterator(*this->index_bases(),origin(),this->shape(),
545 this->strides(),this->index_bases());
549 return iterator(*this->index_bases()+(index)*this->shape(),origin(),
550 this->shape(),this->strides(),
551 this->index_bases());
554 // rbegin() and rend() written naively to thwart MSVC ICE.
555 reverse_iterator rbegin() {
556 reverse_iterator ri(end());
560 reverse_iterator rend() {
561 reverse_iterator ri(begin());
565 // Using declarations don't seem to work for g++
566 // These are the proxies to work around this.
568 const element* origin() const { return super_type::origin(); }
569 const element* data() const { return super_type::data(); }
571 template <class IndexList>
572 const element& operator()(const IndexList& indices) const {
573 boost::function_requires<
574 CollectionConcept<IndexList> >();
575 return super_type::operator()(indices);
578 const_reference operator[](index idx) const {
579 return super_type::access(boost::type<const_reference>(),
581 this->shape(),this->strides(),
582 this->index_bases());
585 // See note attached to generate_array_view in base.hpp
587 typename const_array_view<NDims>::type
588 operator[](const detail::multi_array::
589 index_gen<NumDims,NDims>& indices)
591 return super_type::operator[](indices);
594 const_iterator begin() const {
595 return super_type::begin();
598 const_iterator end() const {
599 return super_type::end();
602 const_reverse_iterator rbegin() const {
603 return super_type::rbegin();
606 const_reverse_iterator rend() const {
607 return super_type::rend();
611 // This is only supplied to support multi_array's default constructor
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) { }
622 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP