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_MULTI_ARRAY_REF_HPP |
14 | #define BOOST_MULTI_ARRAY_MULTI_ARRAY_REF_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 | |
39 | namespace boost { |
40 | |
41 | template <typename T, std::size_t NumDims, |
42 | typename TPtr = const T* |
43 | > |
44 | class 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; |
48 | public: |
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 |
310 | protected: |
311 | #else |
312 | public: |
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 | |
358 | private: |
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 |
384 | protected: |
385 | #else |
386 | public: |
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 | |
411 | template <typename T, std::size_t NumDims> |
412 | class multi_array_ref : |
413 | public const_multi_array_ref<T,NumDims,T*> |
414 | { |
415 | typedef const_multi_array_ref<T,NumDims,T*> super_type; |
416 | public: |
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 | |
610 | protected: |
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 |
623 | |