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;
76 // This ensures that const_multi_array_ref types with different TPtr
77 // types can convert to each other
78 template <typename OPtr>
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_) { }
88 template <typename ExtentList>
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> >();
94 index_base_list_.assign(0);
95 init_multi_array_ref(extents.begin());
98 template <typename ExtentList>
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> >();
105 index_base_list_.assign(0);
106 init_multi_array_ref(extents.begin());
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()) {
114 init_from_extent_gen(ranges);
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) {
123 init_from_extent_gen(ranges);
126 template <class InputIterator>
127 void assign(InputIterator begin, InputIterator end) {
128 boost::function_requires<InputIteratorConcept<InputIterator> >();
130 InputIterator in_iter = begin;
132 std::size_t copy_count=0;
133 while (in_iter != end && copy_count < num_elements_) {
134 *out_iter++ = *in_iter++;
139 template <class BaseList>
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());
146 this->calculate_origin_offset(stride_list_,extent_list_,
147 storage_,index_base_list_);
150 void reindex(index value) {
151 index_base_list_.assign(value);
153 this->calculate_origin_offset(stride_list_,extent_list_,
154 storage_,index_base_list_);
157 template <typename SizeList>
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>()));
165 std::copy(extents.begin(),extents.end(),extent_list_.begin());
166 this->compute_strides(stride_list_,extent_list_,storage_);
169 this->calculate_origin_offset(stride_list_,extent_list_,
170 storage_,index_base_list_);
173 size_type num_dimensions() const { return NumDims; }
175 size_type size() const { return extent_list_.front(); }
177 // given reshaping functionality, this is the max possible size.
178 size_type max_size() const { return num_elements(); }
180 bool empty() const { return size() == 0; }
182 const size_type* shape() const {
183 return extent_list_.data();
186 const index* strides() const {
187 return stride_list_.data();
190 const element* origin() const { return base_+origin_offset_; }
191 const element* data() const { return base_; }
193 size_type num_elements() const { return num_elements_; }
195 const index* index_bases() const {
196 return index_base_list_.data();
200 const storage_order_type& storage_order() const {
204 template <typename IndexList>
205 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&>(),
213 // Only allow const element access
214 const_reference operator[](index idx) const {
215 return super_type::access(boost::type<const_reference>(),
217 shape(),strides(),index_bases());
220 // see generate_array_view in base.hpp
221 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
224 template <int NumDims, int NDims> // else ICE
226 typename const_array_view<NDims>::type
227 operator[](const detail::multi_array::
228 index_gen<NumDims,NDims>& indices)
230 typedef typename const_array_view<NDims>::type return_type;
232 super_type::generate_array_view(boost::type<return_type>(),
240 const_iterator begin() const {
241 return const_iterator(*index_bases(),origin(),
242 shape(),strides(),index_bases());
245 const_iterator end() const {
246 return const_iterator(*index_bases()+(index)*shape(),origin(),
247 shape(),strides(),index_bases());
250 const_reverse_iterator rbegin() const {
251 return const_reverse_iterator(end());
254 const_reverse_iterator rend() const {
255 return const_reverse_iterator(begin());
259 template <typename OPtr>
260 bool operator==(const
261 const_multi_array_ref<T,NumDims,OPtr>& rhs)
263 if(std::equal(extent_list_.begin(),
265 rhs.extent_list_.begin()))
266 return std::equal(begin(),end(),rhs.begin());
270 template <typename OPtr>
272 const_multi_array_ref<T,NumDims,OPtr>& rhs)
274 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
277 template <typename OPtr>
278 bool operator!=(const
279 const_multi_array_ref<T,NumDims,OPtr>& rhs)
281 return !(*this == rhs);
284 template <typename OPtr>
286 const_multi_array_ref<T,NumDims,OPtr>& rhs)
291 template <typename OPtr>
292 bool operator<=(const
293 const_multi_array_ref<T,NumDims,OPtr>& rhs)
295 return !(*this > rhs);
298 template <typename OPtr>
299 bool operator>=(const
300 const_multi_array_ref<T,NumDims,OPtr>& rhs)
302 return !(*this < rhs);
306 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
312 typedef boost::array<size_type,NumDims> size_list;
313 typedef boost::array<index,NumDims> index_list;
315 // This is used by multi_array, which is a subclass of this
316 void set_base_ptr(TPtr new_base) { base_ = new_base; }
319 // This constructor supports multi_array's default constructor
320 // and constructors from multi_array_ref, subarray, and array_view
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)
328 // If index_bases or extents is null, then initialize the corresponding
329 // private data to zeroed lists.
331 boost::detail::multi_array::
332 copy_n(index_bases,NumDims,index_base_list_.begin());
334 std::fill_n(index_base_list_.begin(),NumDims,0);
337 init_multi_array_ref(extents);
339 boost::array<index,NumDims> extent_list;
340 extent_list.assign(0);
341 init_multi_array_ref(extent_list.begin());
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_;
356 // const_multi_array_ref cannot be assigned to (no deep copies!)
357 const_multi_array_ref& operator=(const const_multi_array_ref& other);
359 void init_from_extent_gen(const
360 detail::multi_array::
361 extent_gen<NumDims>& ranges) {
363 typedef boost::array<index,NumDims> extent_list;
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));
370 // calculate the extents
372 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
374 boost::mem_fun_ref(&extent_range::size));
376 init_multi_array_ref(extents.begin());
380 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
386 template <class InputIterator>
387 void init_multi_array_ref(InputIterator extents_iter) {
388 boost::function_requires<InputIteratorConcept<InputIterator> >();
390 boost::detail::multi_array::
391 copy_n(extents_iter,num_dimensions(),extent_list_.begin());
393 // Calculate the array size
394 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
395 size_type(1),std::multiplies<size_type>());
397 this->compute_strides(stride_list_,extent_list_,storage_);
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_,
408 template <typename T, std::size_t NumDims>
409 class multi_array_ref :
410 public const_multi_array_ref<T,NumDims,T*>
412 typedef const_multi_array_ref<T,NumDims,T*> super_type;
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;
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;
431 template <std::size_t NDims>
432 struct const_array_view {
433 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
436 template <std::size_t NDims>
438 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
441 template <class ExtentList>
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> >();
448 template <class ExtentList>
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> >();
457 explicit multi_array_ref(T* base,
458 const detail::multi_array::
459 extent_gen<NumDims>& ranges) :
460 super_type(base,ranges) { }
463 explicit multi_array_ref(T* base,
464 const detail::multi_array::
467 const general_storage_order<NumDims>& so) :
468 super_type(base,ranges,so) { }
471 // Assignment from other ConstMultiArray types.
472 template <typename ConstMultiArray>
473 multi_array_ref& operator=(const ConstMultiArray& other) {
475 detail::multi_array::
476 ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
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(),
482 // iterator-based copy
483 std::copy(other.begin(),other.end(),this->begin());
487 multi_array_ref& operator=(const multi_array_ref& other) {
488 if (&other != this) {
489 // make sure the dimensions agree
491 assert(other.num_dimensions() == this->num_dimensions());
492 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
494 // iterator-based copy
495 std::copy(other.begin(),other.end(),this->begin());
500 element* origin() { return super_type::base_+super_type::origin_offset_; }
502 element* data() { return super_type::base_; }
504 template <class IndexList>
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&>(),
510 indices,this->strides());
514 reference operator[](index idx) {
515 return super_type::access(boost::type<reference>(),
517 this->shape(),this->strides(),
518 this->index_bases());
522 // See note attached to generate_array_view in base.hpp
523 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
526 template <int NumDims, int NDims> // else ICE
528 typename array_view<NDims>::type
529 operator[](const detail::multi_array::
530 index_gen<NumDims,NDims>& indices) {
531 typedef typename array_view<NDims>::type return_type;
533 super_type::generate_array_view(boost::type<return_type>(),
543 return iterator(*this->index_bases(),origin(),this->shape(),
544 this->strides(),this->index_bases());
548 return iterator(*this->index_bases()+(index)*this->shape(),origin(),
549 this->shape(),this->strides(),
550 this->index_bases());
553 // rbegin() and rend() written naively to thwart MSVC ICE.
554 reverse_iterator rbegin() {
555 reverse_iterator ri(end());
559 reverse_iterator rend() {
560 reverse_iterator ri(begin());
564 // Using declarations don't seem to work for g++
565 // These are the proxies to work around this.
567 const element* origin() const { return super_type::origin(); }
568 const element* data() const { return super_type::data(); }
570 template <class IndexList>
571 const element& operator()(const IndexList& indices) const {
572 boost::function_requires<
573 detail::multi_array::CollectionConcept<IndexList> >();
574 return super_type::operator()(indices);
577 const_reference operator[](index idx) const {
578 return super_type::access(boost::type<const_reference>(),
580 this->shape(),this->strides(),
581 this->index_bases());
584 // See note attached to generate_array_view in base.hpp
585 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
588 template <int NumDims, int NDims> // else ICE
590 typename const_array_view<NDims>::type
591 operator[](const detail::multi_array::
592 index_gen<NumDims,NDims>& indices)
594 return super_type::operator[](indices);
597 const_iterator begin() const {
598 return super_type::begin();
601 const_iterator end() const {
602 return super_type::end();
605 const_reverse_iterator rbegin() const {
606 return super_type::rbegin();
609 const_reverse_iterator rend() const {
610 return super_type::rend();
614 // This is only supplied to support multi_array's default constructor
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) { }
625 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP