1// Copyright 2002 The Trustees of Indiana University.
2
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)
6
7// Boost.MultiArray Library
8// Authors: Ronald Garcia
9// Jeremy Siek
10// Andrew Lumsdaine
11// See http://www.boost.org/libs/multi_array for documentation.
12
13#ifndef BOOST_MULTI_ARRAY_REF_RG071801_HPP
14#define BOOST_MULTI_ARRAY_REF_RG071801_HPP
15
16//
17// multi_array_ref.hpp - code for creating "views" of array data.
18//
19
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"
34#include <algorithm>
35#include <cstddef>
36#include <functional>
37#include <numeric>
38
39namespace boost {
40
41template <typename T, std::size_t NumDims,
42 typename TPtr = const T*
43>
44class const_multi_array_ref :
45 public detail::multi_array::multi_array_impl_base<T,NumDims>
46{
47 typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
48public:
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;
59
60 // template typedefs
61 template <std::size_t NDims>
62 struct const_array_view {
63 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
64 };
65
66 template <std::size_t NDims>
67 struct array_view {
68 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
69 };
70
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;
75#endif
76
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_) { }
88
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> >();
94
95 index_base_list_.assign(0);
96 init_multi_array_ref(extents.begin());
97 }
98
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> >();
105
106 index_base_list_.assign(0);
107 init_multi_array_ref(extents.begin());
108 }
109
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()) {
114
115 init_from_extent_gen(ranges);
116 }
117
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) {
123
124 init_from_extent_gen(ranges);
125 }
126
127 template <class InputIterator>
128 void assign(InputIterator begin, InputIterator end) {
129 boost::function_requires<InputIteratorConcept<InputIterator> >();
130
131 InputIterator in_iter = begin;
132 T* out_iter = base_;
133 std::size_t copy_count=0;
134 while (in_iter != end && copy_count < num_elements_) {
135 *out_iter++ = *in_iter++;
136 copy_count++;
137 }
138 }
139
140 template <class BaseList>
141#ifdef BOOST_NO_SFINAE
142 void
143#else
144 typename
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());
152 origin_offset_ =
153 this->calculate_origin_offset(stride_list_,extent_list_,
154 storage_,index_base_list_);
155 }
156
157 void reindex(index value) {
158 index_base_list_.assign(value);
159 origin_offset_ =
160 this->calculate_origin_offset(stride_list_,extent_list_,
161 storage_,index_base_list_);
162 }
163
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>()));
171
172 std::copy(extents.begin(),extents.end(),extent_list_.begin());
173 this->compute_strides(stride_list_,extent_list_,storage_);
174
175 origin_offset_ =
176 this->calculate_origin_offset(stride_list_,extent_list_,
177 storage_,index_base_list_);
178 }
179
180 size_type num_dimensions() const { return NumDims; }
181
182 size_type size() const { return extent_list_.front(); }
183
184 // given reshaping functionality, this is the max possible size.
185 size_type max_size() const { return num_elements(); }
186
187 bool empty() const { return size() == 0; }
188
189 const size_type* shape() const {
190 return extent_list_.data();
191 }
192
193 const index* strides() const {
194 return stride_list_.data();
195 }
196
197 const element* origin() const { return base_+origin_offset_; }
198 const element* data() const { return base_; }
199
200 size_type num_elements() const { return num_elements_; }
201
202 const index* index_bases() const {
203 return index_base_list_.data();
204 }
205
206
207 const storage_order_type& storage_order() const {
208 return storage_;
209 }
210
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&>(),
216 indices,origin(),
217 shape(),strides(),index_bases());
218 }
219
220 // Only allow const element access
221 const_reference operator[](index idx) const {
222 return super_type::access(boost::type<const_reference>(),
223 idx,origin(),
224 shape(),strides(),index_bases());
225 }
226
227 // see generate_array_view in base.hpp
228 template <int NDims>
229 typename const_array_view<NDims>::type
230 operator[](const detail::multi_array::
231 index_gen<NumDims,NDims>& indices)
232 const {
233 typedef typename const_array_view<NDims>::type return_type;
234 return
235 super_type::generate_array_view(boost::type<return_type>(),
236 indices,
237 shape(),
238 strides(),
239 index_bases(),
240 origin());
241 }
242
243 const_iterator begin() const {
244 return const_iterator(*index_bases(),origin(),
245 shape(),strides(),index_bases());
246 }
247
248 const_iterator end() const {
249 return const_iterator(*index_bases()+(index)*shape(),origin(),
250 shape(),strides(),index_bases());
251 }
252
253 const_reverse_iterator rbegin() const {
254 return const_reverse_iterator(end());
255 }
256
257 const_reverse_iterator rend() const {
258 return const_reverse_iterator(begin());
259 }
260
261
262 template <typename OPtr>
263 bool operator==(const
264 const_multi_array_ref<T,NumDims,OPtr>& rhs)
265 const {
266 if(std::equal(extent_list_.begin(),
267 extent_list_.end(),
268 rhs.extent_list_.begin()))
269 return std::equal(begin(),end(),rhs.begin());
270 else return false;
271 }
272
273 template <typename OPtr>
274 bool operator<(const
275 const_multi_array_ref<T,NumDims,OPtr>& rhs)
276 const {
277 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
278 }
279
280 template <typename OPtr>
281 bool operator!=(const
282 const_multi_array_ref<T,NumDims,OPtr>& rhs)
283 const {
284 return !(*this == rhs);
285 }
286
287 template <typename OPtr>
288 bool operator>(const
289 const_multi_array_ref<T,NumDims,OPtr>& rhs)
290 const {
291 return rhs < *this;
292 }
293
294 template <typename OPtr>
295 bool operator<=(const
296 const_multi_array_ref<T,NumDims,OPtr>& rhs)
297 const {
298 return !(*this > rhs);
299 }
300
301 template <typename OPtr>
302 bool operator>=(const
303 const_multi_array_ref<T,NumDims,OPtr>& rhs)
304 const {
305 return !(*this < rhs);
306 }
307
308
309#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
310protected:
311#else
312public:
313#endif
314
315 typedef boost::array<size_type,NumDims> size_list;
316 typedef boost::array<index,NumDims> index_list;
317
318 // This is used by multi_array, which is a subclass of this
319 void set_base_ptr(TPtr new_base) { base_ = new_base; }
320
321
322 // This constructor supports multi_array's default constructor
323 // and constructors from multi_array_ref, subarray, and array_view
324 explicit
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)
330 {
331 // If index_bases or extents is null, then initialize the corresponding
332 // private data to zeroed lists.
333 if(index_bases) {
334 boost::detail::multi_array::
335 copy_n(index_bases,NumDims,index_base_list_.begin());
336 } else {
337 std::fill_n(index_base_list_.begin(),NumDims,0);
338 }
339 if(extents) {
340 init_multi_array_ref(extents);
341 } else {
342 boost::array<index,NumDims> extent_list;
343 extent_list.assign(0);
344 init_multi_array_ref(extent_list.begin());
345 }
346 }
347
348
349 TPtr base_;
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_;
357
358private:
359 // const_multi_array_ref cannot be assigned to (no deep copies!)
360 const_multi_array_ref& operator=(const const_multi_array_ref& other);
361
362 void init_from_extent_gen(const
363 detail::multi_array::
364 extent_gen<NumDims>& ranges) {
365
366 typedef boost::array<index,NumDims> extent_list;
367
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));
372
373 // calculate the extents
374 extent_list extents;
375 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
376 extents.begin(),
377 boost::mem_fun_ref(&extent_range::size));
378
379 init_multi_array_ref(extents.begin());
380 }
381
382
383#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
384protected:
385#else
386public:
387#endif
388 // RG - move me!
389 template <class InputIterator>
390 void init_multi_array_ref(InputIterator extents_iter) {
391 boost::function_requires<InputIteratorConcept<InputIterator> >();
392
393 boost::detail::multi_array::
394 copy_n(extents_iter,num_dimensions(),extent_list_.begin());
395
396 // Calculate the array size
397 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
398 size_type(1),std::multiplies<size_type>());
399
400 this->compute_strides(stride_list_,extent_list_,storage_);
401
402 origin_offset_ =
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_,
407 storage_);
408 }
409};
410
411template <typename T, std::size_t NumDims>
412class multi_array_ref :
413 public const_multi_array_ref<T,NumDims,T*>
414{
415 typedef const_multi_array_ref<T,NumDims,T*> super_type;
416public:
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;
429
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;
433
434 template <std::size_t NDims>
435 struct const_array_view {
436 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
437 };
438
439 template <std::size_t NDims>
440 struct array_view {
441 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
442 };
443
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> >();
449 }
450
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> >();
457 }
458
459
460 explicit multi_array_ref(T* base,
461 const detail::multi_array::
462 extent_gen<NumDims>& ranges) :
463 super_type(base,ranges) { }
464
465
466 explicit multi_array_ref(T* base,
467 const detail::multi_array::
468 extent_gen<NumDims>&
469 ranges,
470 const general_storage_order<NumDims>& so) :
471 super_type(base,ranges,so) { }
472
473
474 // Assignment from other ConstMultiArray types.
475 template <typename ConstMultiArray>
476 multi_array_ref& operator=(const ConstMultiArray& other) {
477 function_requires<
478 multi_array_concepts::
479 ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
480
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(),
484 this->shape()));
485 // iterator-based copy
486 std::copy(other.begin(),other.end(),this->begin());
487 return *this;
488 }
489
490 multi_array_ref& operator=(const multi_array_ref& other) {
491 if (&other != this) {
492 // make sure the dimensions agree
493
494 BOOST_ASSERT(other.num_dimensions() == this->num_dimensions());
495 BOOST_ASSERT(std::equal(other.shape(),
496 other.shape()+this->num_dimensions(),
497 this->shape()));
498 // iterator-based copy
499 std::copy(other.begin(),other.end(),this->begin());
500 }
501 return *this;
502 }
503
504 element* origin() { return super_type::base_+super_type::origin_offset_; }
505
506 element* data() { return super_type::base_; }
507
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&>(),
513 indices,origin(),
514 this->shape(),this->strides(),
515 this->index_bases());
516 }
517
518
519 reference operator[](index idx) {
520 return super_type::access(boost::type<reference>(),
521 idx,origin(),
522 this->shape(),this->strides(),
523 this->index_bases());
524 }
525
526
527 // See note attached to generate_array_view in base.hpp
528 template <int NDims>
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;
533 return
534 super_type::generate_array_view(boost::type<return_type>(),
535 indices,
536 this->shape(),
537 this->strides(),
538 this->index_bases(),
539 origin());
540 }
541
542
543 iterator begin() {
544 return iterator(*this->index_bases(),origin(),this->shape(),
545 this->strides(),this->index_bases());
546 }
547
548 iterator end() {
549 return iterator(*this->index_bases()+(index)*this->shape(),origin(),
550 this->shape(),this->strides(),
551 this->index_bases());
552 }
553
554 // rbegin() and rend() written naively to thwart MSVC ICE.
555 reverse_iterator rbegin() {
556 reverse_iterator ri(end());
557 return ri;
558 }
559
560 reverse_iterator rend() {
561 reverse_iterator ri(begin());
562 return ri;
563 }
564
565 // Using declarations don't seem to work for g++
566 // These are the proxies to work around this.
567
568 const element* origin() const { return super_type::origin(); }
569 const element* data() const { return super_type::data(); }
570
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);
576 }
577
578 const_reference operator[](index idx) const {
579 return super_type::access(boost::type<const_reference>(),
580 idx,origin(),
581 this->shape(),this->strides(),
582 this->index_bases());
583 }
584
585 // See note attached to generate_array_view in base.hpp
586 template <int NDims>
587 typename const_array_view<NDims>::type
588 operator[](const detail::multi_array::
589 index_gen<NumDims,NDims>& indices)
590 const {
591 return super_type::operator[](indices);
592 }
593
594 const_iterator begin() const {
595 return super_type::begin();
596 }
597
598 const_iterator end() const {
599 return super_type::end();
600 }
601
602 const_reverse_iterator rbegin() const {
603 return super_type::rbegin();
604 }
605
606 const_reverse_iterator rend() const {
607 return super_type::rend();
608 }
609
610protected:
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) { }
617
618};
619
620} // namespace boost
621
622#endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP
623