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/array.hpp"
30 #include "boost/concept_check.hpp"
31 #include "boost/functional.hpp"
32 #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 detail::multi_array::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 detail::multi_array::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 detail::multi_array::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 detail::multi_array::CollectionConcept<SizeList> >();
168 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 detail::multi_array::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
228 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
231 template <int NumDims, int NDims> // else ICE
233 typename const_array_view<NDims>::type
234 operator[](const detail::multi_array::
235 index_gen<NumDims,NDims>& indices)
237 typedef typename const_array_view<NDims>::type return_type;
239 super_type::generate_array_view(boost::type<return_type>(),
247 const_iterator begin() const {
248 return const_iterator(*index_bases(),origin(),
249 shape(),strides(),index_bases());
252 const_iterator end() const {
253 return const_iterator(*index_bases()+(index)*shape(),origin(),
254 shape(),strides(),index_bases());
257 const_reverse_iterator rbegin() const {
258 return const_reverse_iterator(end());
261 const_reverse_iterator rend() const {
262 return const_reverse_iterator(begin());
266 template <typename OPtr>
267 bool operator==(const
268 const_multi_array_ref<T,NumDims,OPtr>& rhs)
270 if(std::equal(extent_list_.begin(),
272 rhs.extent_list_.begin()))
273 return std::equal(begin(),end(),rhs.begin());
277 template <typename OPtr>
279 const_multi_array_ref<T,NumDims,OPtr>& rhs)
281 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
284 template <typename OPtr>
285 bool operator!=(const
286 const_multi_array_ref<T,NumDims,OPtr>& rhs)
288 return !(*this == rhs);
291 template <typename OPtr>
293 const_multi_array_ref<T,NumDims,OPtr>& rhs)
298 template <typename OPtr>
299 bool operator<=(const
300 const_multi_array_ref<T,NumDims,OPtr>& rhs)
302 return !(*this > rhs);
305 template <typename OPtr>
306 bool operator>=(const
307 const_multi_array_ref<T,NumDims,OPtr>& rhs)
309 return !(*this < rhs);
313 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
319 typedef boost::array<size_type,NumDims> size_list;
320 typedef boost::array<index,NumDims> index_list;
322 // This is used by multi_array, which is a subclass of this
323 void set_base_ptr(TPtr new_base) { base_ = new_base; }
326 // This constructor supports multi_array's default constructor
327 // and constructors from multi_array_ref, subarray, and array_view
329 const_multi_array_ref(TPtr base,
330 const storage_order_type& so,
331 const index * index_bases,
332 const size_type* extents) :
333 base_(base), storage_(so), origin_offset_(0), directional_offset_(0)
335 // If index_bases or extents is null, then initialize the corresponding
336 // private data to zeroed lists.
338 boost::detail::multi_array::
339 copy_n(index_bases,NumDims,index_base_list_.begin());
341 std::fill_n(index_base_list_.begin(),NumDims,0);
344 init_multi_array_ref(extents);
346 boost::array<index,NumDims> extent_list;
347 extent_list.assign(0);
348 init_multi_array_ref(extent_list.begin());
354 storage_order_type storage_;
355 size_list extent_list_;
356 index_list stride_list_;
357 index_list index_base_list_;
358 index origin_offset_;
359 index directional_offset_;
360 size_type num_elements_;
363 // const_multi_array_ref cannot be assigned to (no deep copies!)
364 const_multi_array_ref& operator=(const const_multi_array_ref& other);
366 void init_from_extent_gen(const
367 detail::multi_array::
368 extent_gen<NumDims>& ranges) {
370 typedef boost::array<index,NumDims> extent_list;
372 // get the index_base values
373 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
374 index_base_list_.begin(),
375 boost::mem_fun_ref(&extent_range::start));
377 // calculate the extents
379 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
381 boost::mem_fun_ref(&extent_range::size));
383 init_multi_array_ref(extents.begin());
387 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
393 template <class InputIterator>
394 void init_multi_array_ref(InputIterator extents_iter) {
395 boost::function_requires<InputIteratorConcept<InputIterator> >();
397 boost::detail::multi_array::
398 copy_n(extents_iter,num_dimensions(),extent_list_.begin());
400 // Calculate the array size
401 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
402 size_type(1),std::multiplies<size_type>());
404 this->compute_strides(stride_list_,extent_list_,storage_);
407 this->calculate_origin_offset(stride_list_,extent_list_,
408 storage_,index_base_list_);
409 directional_offset_ =
410 this->calculate_descending_dimension_offset(stride_list_,extent_list_,
415 template <typename T, std::size_t NumDims>
416 class multi_array_ref :
417 public const_multi_array_ref<T,NumDims,T*>
419 typedef const_multi_array_ref<T,NumDims,T*> super_type;
421 typedef typename super_type::value_type value_type;
422 typedef typename super_type::reference reference;
423 typedef typename super_type::iterator iterator;
424 typedef typename super_type::reverse_iterator reverse_iterator;
425 typedef typename super_type::const_reference const_reference;
426 typedef typename super_type::const_iterator const_iterator;
427 typedef typename super_type::const_reverse_iterator const_reverse_iterator;
428 typedef typename super_type::element element;
429 typedef typename super_type::size_type size_type;
430 typedef typename super_type::difference_type difference_type;
431 typedef typename super_type::index index;
432 typedef typename super_type::extent_range extent_range;
434 typedef typename super_type::storage_order_type storage_order_type;
435 typedef typename super_type::index_list index_list;
436 typedef typename super_type::size_list size_list;
438 template <std::size_t NDims>
439 struct const_array_view {
440 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
443 template <std::size_t NDims>
445 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
448 template <class ExtentList>
449 explicit multi_array_ref(T* base, const ExtentList& extents) :
450 super_type(base,extents) {
451 boost::function_requires<
452 detail::multi_array::CollectionConcept<ExtentList> >();
455 template <class ExtentList>
456 explicit multi_array_ref(T* base, const ExtentList& extents,
457 const general_storage_order<NumDims>& so) :
458 super_type(base,extents,so) {
459 boost::function_requires<
460 detail::multi_array::CollectionConcept<ExtentList> >();
464 explicit multi_array_ref(T* base,
465 const detail::multi_array::
466 extent_gen<NumDims>& ranges) :
467 super_type(base,ranges) { }
470 explicit multi_array_ref(T* base,
471 const detail::multi_array::
474 const general_storage_order<NumDims>& so) :
475 super_type(base,ranges,so) { }
478 // Assignment from other ConstMultiArray types.
479 template <typename ConstMultiArray>
480 multi_array_ref& operator=(const ConstMultiArray& other) {
482 detail::multi_array::
483 ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
485 // make sure the dimensions agree
486 assert(other.num_dimensions() == this->num_dimensions());
487 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
489 // iterator-based copy
490 std::copy(other.begin(),other.end(),this->begin());
494 multi_array_ref& operator=(const multi_array_ref& other) {
495 if (&other != this) {
496 // make sure the dimensions agree
498 assert(other.num_dimensions() == this->num_dimensions());
499 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
501 // iterator-based copy
502 std::copy(other.begin(),other.end(),this->begin());
507 element* origin() { return super_type::base_+super_type::origin_offset_; }
509 element* data() { return super_type::base_; }
511 template <class IndexList>
512 element& operator()(const IndexList& indices) {
513 boost::function_requires<
514 detail::multi_array::CollectionConcept<IndexList> >();
515 return super_type::access_element(boost::type<element&>(),
517 this->shape(),this->strides(),
518 this->index_bases());
522 reference operator[](index idx) {
523 return super_type::access(boost::type<reference>(),
525 this->shape(),this->strides(),
526 this->index_bases());
530 // See note attached to generate_array_view in base.hpp
531 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
534 template <int NumDims, int NDims> // else ICE
536 typename array_view<NDims>::type
537 operator[](const detail::multi_array::
538 index_gen<NumDims,NDims>& indices) {
539 typedef typename array_view<NDims>::type return_type;
541 super_type::generate_array_view(boost::type<return_type>(),
551 return iterator(*this->index_bases(),origin(),this->shape(),
552 this->strides(),this->index_bases());
556 return iterator(*this->index_bases()+(index)*this->shape(),origin(),
557 this->shape(),this->strides(),
558 this->index_bases());
561 // rbegin() and rend() written naively to thwart MSVC ICE.
562 reverse_iterator rbegin() {
563 reverse_iterator ri(end());
567 reverse_iterator rend() {
568 reverse_iterator ri(begin());
572 // Using declarations don't seem to work for g++
573 // These are the proxies to work around this.
575 const element* origin() const { return super_type::origin(); }
576 const element* data() const { return super_type::data(); }
578 template <class IndexList>
579 const element& operator()(const IndexList& indices) const {
580 boost::function_requires<
581 detail::multi_array::CollectionConcept<IndexList> >();
582 return super_type::operator()(indices);
585 const_reference operator[](index idx) const {
586 return super_type::access(boost::type<const_reference>(),
588 this->shape(),this->strides(),
589 this->index_bases());
592 // See note attached to generate_array_view in base.hpp
593 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
596 template <int NumDims, int NDims> // else ICE
598 typename const_array_view<NDims>::type
599 operator[](const detail::multi_array::
600 index_gen<NumDims,NDims>& indices)
602 return super_type::operator[](indices);
605 const_iterator begin() const {
606 return super_type::begin();
609 const_iterator end() const {
610 return super_type::end();
613 const_reverse_iterator rbegin() const {
614 return super_type::rbegin();
617 const_reverse_iterator rend() const {
618 return super_type::rend();
622 // This is only supplied to support multi_array's default constructor
623 explicit multi_array_ref(T* base,
624 const storage_order_type& so,
625 const index* index_bases,
626 const size_type* extents) :
627 super_type(base,so,index_bases,extents) { }
633 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP