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::copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
145 this->calculate_origin_offset(stride_list_,extent_list_,
146 storage_,index_base_list_);
149 void reindex(index value) {
150 index_base_list_.assign(value);
152 this->calculate_origin_offset(stride_list_,extent_list_,
153 storage_,index_base_list_);
156 template <typename SizeList>
157 void reshape(const SizeList& extents) {
158 boost::function_requires<
159 detail::multi_array::CollectionConcept<SizeList> >();
160 assert(num_elements_ ==
161 std::accumulate(extents.begin(),extents.end(),
162 size_type(1),std::multiplies<size_type>()));
164 std::copy(extents.begin(),extents.end(),extent_list_.begin());
165 this->compute_strides(stride_list_,extent_list_,storage_);
168 this->calculate_origin_offset(stride_list_,extent_list_,
169 storage_,index_base_list_);
172 size_type num_dimensions() const { return NumDims; }
174 size_type size() const { return extent_list_.front(); }
176 // given reshaping functionality, this is the max possible size.
177 size_type max_size() const { return num_elements(); }
179 bool empty() const { return size() == 0; }
181 const size_type* shape() const {
182 return extent_list_.data();
185 const index* strides() const {
186 return stride_list_.data();
189 const element* origin() const { return base_+origin_offset_; }
190 const element* data() const { return base_; }
192 size_type num_elements() const { return num_elements_; }
194 const index* index_bases() const {
195 return index_base_list_.data();
199 const storage_order_type& storage_order() const {
203 template <typename IndexList>
204 const element& operator()(IndexList indices) const {
205 boost::function_requires<
206 detail::multi_array::CollectionConcept<IndexList> >();
207 return super_type::access_element(boost::type<const element&>(),
212 // Only allow const element access
213 const_reference operator[](index idx) const {
214 return super_type::access(boost::type<const_reference>(),
216 shape(),strides(),index_bases());
219 // see generate_array_view in base.hpp
220 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
223 template <int NumDims, int NDims> // else ICE
225 typename const_array_view<NDims>::type
226 operator[](const detail::multi_array::
227 index_gen<NumDims,NDims>& indices)
229 typedef typename const_array_view<NDims>::type return_type;
231 super_type::generate_array_view(boost::type<return_type>(),
239 const_iterator begin() const {
240 return const_iterator(*index_bases(),origin(),
241 shape(),strides(),index_bases());
244 const_iterator end() const {
245 return const_iterator(*index_bases()+*shape(),origin(),
246 shape(),strides(),index_bases());
249 const_reverse_iterator rbegin() const {
250 return const_reverse_iterator(end());
253 const_reverse_iterator rend() const {
254 return const_reverse_iterator(begin());
258 template <typename OPtr>
259 bool operator==(const
260 const_multi_array_ref<T,NumDims,OPtr>& rhs)
262 if(std::equal(extent_list_.begin(),
264 rhs.extent_list_.begin()))
265 return std::equal(begin(),end(),rhs.begin());
269 template <typename OPtr>
271 const_multi_array_ref<T,NumDims,OPtr>& rhs)
273 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
276 template <typename OPtr>
277 bool operator!=(const
278 const_multi_array_ref<T,NumDims,OPtr>& rhs)
280 return !(*this == rhs);
283 template <typename OPtr>
285 const_multi_array_ref<T,NumDims,OPtr>& rhs)
290 template <typename OPtr>
291 bool operator<=(const
292 const_multi_array_ref<T,NumDims,OPtr>& rhs)
294 return !(*this > rhs);
297 template <typename OPtr>
298 bool operator>=(const
299 const_multi_array_ref<T,NumDims,OPtr>& rhs)
301 return !(*this < rhs);
305 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
311 typedef boost::array<size_type,NumDims> size_list;
312 typedef boost::array<index,NumDims> index_list;
314 // This is used by multi_array, which is a subclass of this
315 void set_base_ptr(TPtr new_base) { base_ = new_base; }
318 // This constructor supports multi_array's default constructor
319 // and constructors from multi_array_ref, subarray, and array_view
321 const_multi_array_ref(TPtr base,
322 const storage_order_type& so,
323 const index * index_bases,
324 const size_type* extents) :
325 base_(base), storage_(so), origin_offset_(0), directional_offset_(0)
327 // If index_bases or extents is null, then initialize the corresponding
328 // private data to zeroed lists.
330 boost::copy_n(index_bases,NumDims,index_base_list_.begin());
332 std::fill_n(index_base_list_.begin(),NumDims,0);
335 init_multi_array_ref(extents);
337 boost::array<index,NumDims> extent_list;
338 extent_list.assign(0);
339 init_multi_array_ref(extent_list.begin());
345 storage_order_type storage_;
346 size_list extent_list_;
347 index_list stride_list_;
348 index_list index_base_list_;
349 index origin_offset_;
350 index directional_offset_;
351 size_type num_elements_;
354 // const_multi_array_ref cannot be assigned to (no deep copies!)
355 const_multi_array_ref& operator=(const const_multi_array_ref& other);
357 void init_from_extent_gen(const
358 detail::multi_array::
359 extent_gen<NumDims>& ranges) {
361 typedef boost::array<index,NumDims> extent_list;
363 // get the index_base values
364 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
365 index_base_list_.begin(),
366 boost::mem_fun_ref(&extent_range::start));
368 // calculate the extents
370 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
372 boost::mem_fun_ref(&extent_range::size));
374 init_multi_array_ref(extents.begin());
378 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
384 template <class InputIterator>
385 void init_multi_array_ref(InputIterator extents_iter) {
386 boost::function_requires<InputIteratorConcept<InputIterator> >();
388 boost::copy_n(extents_iter,num_dimensions(),extent_list_.begin());
390 // Calculate the array size
391 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
392 1,std::multiplies<index>());
394 this->compute_strides(stride_list_,extent_list_,storage_);
397 this->calculate_origin_offset(stride_list_,extent_list_,
398 storage_,index_base_list_);
399 directional_offset_ =
400 this->calculate_descending_dimension_offset(stride_list_,extent_list_,
405 template <typename T, std::size_t NumDims>
406 class multi_array_ref :
407 public const_multi_array_ref<T,NumDims,T*>
409 typedef const_multi_array_ref<T,NumDims,T*> super_type;
411 typedef typename super_type::value_type value_type;
412 typedef typename super_type::reference reference;
413 typedef typename super_type::iterator iterator;
414 typedef typename super_type::reverse_iterator reverse_iterator;
415 typedef typename super_type::const_reference const_reference;
416 typedef typename super_type::const_iterator const_iterator;
417 typedef typename super_type::const_reverse_iterator const_reverse_iterator;
418 typedef typename super_type::element element;
419 typedef typename super_type::size_type size_type;
420 typedef typename super_type::difference_type difference_type;
421 typedef typename super_type::index index;
422 typedef typename super_type::extent_range extent_range;
424 typedef typename super_type::storage_order_type storage_order_type;
425 typedef typename super_type::index_list index_list;
426 typedef typename super_type::size_list size_list;
428 template <std::size_t NDims>
429 struct const_array_view {
430 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
433 template <std::size_t NDims>
435 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
438 template <class ExtentList>
439 explicit multi_array_ref(T* base, const ExtentList& extents) :
440 super_type(base,extents) {
441 boost::function_requires<
442 detail::multi_array::CollectionConcept<ExtentList> >();
445 template <class ExtentList>
446 explicit multi_array_ref(T* base, const ExtentList& extents,
447 const general_storage_order<NumDims>& so) :
448 super_type(base,extents,so) {
449 boost::function_requires<
450 detail::multi_array::CollectionConcept<ExtentList> >();
454 explicit multi_array_ref(T* base,
455 const detail::multi_array::
456 extent_gen<NumDims>& ranges) :
457 super_type(base,ranges) { }
460 explicit multi_array_ref(T* base,
461 const detail::multi_array::
464 const general_storage_order<NumDims>& so) :
465 super_type(base,ranges,so) { }
468 // Assignment from other ConstMultiArray types.
469 template <typename ConstMultiArray>
470 multi_array_ref& operator=(const ConstMultiArray& other) {
472 detail::multi_array::
473 ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
475 // make sure the dimensions agree
476 assert(other.num_dimensions() == this->num_dimensions());
477 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
479 // iterator-based copy
480 std::copy(other.begin(),other.end(),this->begin());
484 multi_array_ref& operator=(const multi_array_ref& other) {
485 if (&other != this) {
486 // make sure the dimensions agree
488 assert(other.num_dimensions() == this->num_dimensions());
489 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
491 // iterator-based copy
492 std::copy(other.begin(),other.end(),this->begin());
497 element* origin() { return super_type::base_+super_type::origin_offset_; }
499 element* data() { return super_type::base_; }
501 template <class IndexList>
502 element& operator()(const IndexList& indices) {
503 boost::function_requires<
504 detail::multi_array::CollectionConcept<IndexList> >();
505 return super_type::access_element(boost::type<element&>(),
507 indices,this->strides());
511 reference operator[](index idx) {
512 return super_type::access(boost::type<reference>(),
514 this->shape(),this->strides(),
515 this->index_bases());
519 // See note attached to generate_array_view in base.hpp
520 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
523 template <int NumDims, int NDims> // else ICE
525 typename array_view<NDims>::type
526 operator[](const detail::multi_array::
527 index_gen<NumDims,NDims>& indices) {
528 typedef typename array_view<NDims>::type return_type;
530 super_type::generate_array_view(boost::type<return_type>(),
540 return iterator(*this->index_bases(),origin(),this->shape(),
541 this->strides(),this->index_bases());
545 return iterator(*this->index_bases()+*this->shape(),origin(),
546 this->shape(),this->strides(),
547 this->index_bases());
550 // rbegin() and rend() written naively to thwart MSVC ICE.
551 reverse_iterator rbegin() {
552 reverse_iterator ri(end());
556 reverse_iterator rend() {
557 reverse_iterator ri(begin());
561 // Using declarations don't seem to work for g++
562 // These are the proxies to work around this.
564 const element* origin() const { return super_type::origin(); }
565 const element* data() const { return super_type::data(); }
567 template <class IndexList>
568 const element& operator()(const IndexList& indices) const {
569 boost::function_requires<
570 detail::multi_array::CollectionConcept<IndexList> >();
571 return super_type::operator()(indices);
574 const_reference operator[](index idx) const {
575 return super_type::access(boost::type<const_reference>(),
577 this->shape(),this->strides(),
578 this->index_bases());
581 // See note attached to generate_array_view in base.hpp
582 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
585 template <int NumDims, int NDims> // else ICE
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