1 // Copyright (C) 2002 Ronald Garcia
3 // Permission to copy, use, sell and distribute this software is granted
4 // provided this copyright notice appears in all copies.
5 // Permission to modify the code and to distribute modified code is granted
6 // provided this copyright notice appears in all copies, and a notice
7 // that the code was modified is included with the copyright notice.
9 // This software is provided "as is" without express or implied warranty,
10 // and with no claim as to its suitability for any purpose.
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_iter_base const_iter_base;
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;
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 template <typename OPtr>
78 const_multi_array_ref(const const_multi_array_ref<T,NumDims,
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 calculate_origin_offset(stride_list_,extent_list_,
146 storage_,index_base_list_);
149 void reindex(index value) {
150 index_base_list_.assign(value);
152 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 compute_strides(stride_list_,extent_list_,storage_);
168 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();
198 template <typename IndexList>
199 const element& operator()(IndexList indices) const {
200 boost::function_requires<
201 detail::multi_array::CollectionConcept<IndexList> >();
202 return super_type::access_element(boost::type<const element&>(),
207 // Only allow const element access
208 const_reference operator[](index idx) const {
209 return super_type::access(boost::type<const_reference>(),
211 shape(),strides(),index_bases());
214 // see generate_array_view in base.hpp
215 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
218 template <int NumDims, int NDims> // else ICE
220 typename const_array_view<NDims>::type
221 operator[](const detail::multi_array::
222 index_gen<NumDims,NDims>& indices)
224 typedef typename const_array_view<NDims>::type return_type;
226 super_type::generate_array_view(boost::type<return_type>(),
234 const_iterator begin() const {
235 return const_iterator(const_iter_base(*index_bases(),origin(),
236 shape(),strides(),index_bases()));
239 const_iterator end() const {
240 return const_iterator(const_iter_base(*index_bases()+*shape(),origin(),
241 shape(),strides(),index_bases()));
244 const_reverse_iterator rbegin() const {
245 return const_reverse_iterator(end());
248 const_reverse_iterator rend() const {
249 return const_reverse_iterator(begin());
253 template <typename OPtr>
254 bool operator==(const
255 const_multi_array_ref<T,NumDims,OPtr>& rhs)
257 if(std::equal(extent_list_.begin(),
259 rhs.extent_list_.begin()))
260 return std::equal(begin(),end(),rhs.begin());
264 template <typename OPtr>
266 const_multi_array_ref<T,NumDims,OPtr>& rhs)
268 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
271 template <typename OPtr>
272 bool operator!=(const
273 const_multi_array_ref<T,NumDims,OPtr>& rhs)
275 return !(*this == rhs);
278 template <typename OPtr>
280 const_multi_array_ref<T,NumDims,OPtr>& rhs)
285 template <typename OPtr>
286 bool operator<=(const
287 const_multi_array_ref<T,NumDims,OPtr>& rhs)
289 return !(*this > rhs);
292 template <typename OPtr>
293 bool operator>=(const
294 const_multi_array_ref<T,NumDims,OPtr>& rhs)
296 return !(*this < rhs);
299 // This ensures that const_multi_array_ref types with different TPtr
300 // types can convert to each other
301 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
306 // This is used by multi_array, which is a subclass of this
307 void set_base_ptr(TPtr new_base) { base_ = new_base; }
309 template <typename OPtr>
310 const_multi_array_ref(const detail::multi_array::
311 const_sub_array<T,NumDims,OPtr>& rhs)
312 : base_(rhs.origin()),
313 storage_(c_storage_order()),
314 origin_offset_(0), directional_offset_(0),
315 num_elements_(rhs.num_elements())
318 copy_n(rhs.shape(),rhs.num_dimensions(),extent_list_.begin());
319 copy_n(rhs.strides(),rhs.num_dimensions(),stride_list_.begin());
320 copy_n(rhs.index_bases(),rhs.num_dimensions(),index_base_list_.begin());
323 typedef boost::array<size_type,NumDims> size_list;
324 typedef boost::array<index,NumDims> index_list;
327 general_storage_order<NumDims> storage_;
328 size_list extent_list_;
329 index_list stride_list_;
330 index_list index_base_list_;
331 index origin_offset_;
332 index directional_offset_;
333 size_type num_elements_;
336 // const_multi_array_ref cannot be assigned to (no deep copies!)
337 const_multi_array_ref& operator=(const const_multi_array_ref& other);
339 void init_from_extent_gen(const
340 detail::multi_array::
341 extent_gen<NumDims>& ranges) {
343 typedef boost::array<index,NumDims> extent_list;
345 // get the index_base values
346 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
347 index_base_list_.begin(),
348 boost::mem_fun_ref(&extent_range::start));
350 // calculate the extents
352 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
354 boost::mem_fun_ref(&extent_range::size));
356 init_multi_array_ref(extents.begin());
360 template <class InputIterator>
361 void init_multi_array_ref(InputIterator extents_iter) {
362 boost::function_requires<InputIteratorConcept<InputIterator> >();
364 boost::copy_n(extents_iter,num_dimensions(),extent_list_.begin());
366 // Calculate the array size
367 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
368 1,std::multiplies<index>());
369 assert(num_elements_ != 0);
371 compute_strides(stride_list_,extent_list_,storage_);
374 calculate_origin_offset(stride_list_,extent_list_,
375 storage_,index_base_list_);
376 directional_offset_ =
377 calculate_descending_dimension_offset(stride_list_,extent_list_,
383 template <typename T, std::size_t NumDims>
384 class multi_array_ref :
385 public const_multi_array_ref<T,NumDims,T*>
387 typedef const_multi_array_ref<T,NumDims,T*> super_type;
389 typedef typename super_type::value_type value_type;
390 typedef typename super_type::reference reference;
391 typedef typename super_type::iterator iterator;
392 typedef typename super_type::iter_base iter_base;
393 typedef typename super_type::reverse_iterator reverse_iterator;
394 typedef typename super_type::const_reference const_reference;
395 typedef typename super_type::const_iterator const_iterator;
396 typedef typename super_type::const_iter_base const_iter_base;
397 typedef typename super_type::const_reverse_iterator const_reverse_iterator;
398 typedef typename super_type::element element;
399 typedef typename super_type::size_type size_type;
400 typedef typename super_type::difference_type difference_type;
401 typedef typename super_type::index index;
402 typedef typename super_type::extent_range extent_range;
406 template <std::size_t NDims>
407 struct const_array_view {
408 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
411 template <std::size_t NDims>
413 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
416 template <class ExtentList>
417 explicit multi_array_ref(T* base, const ExtentList& extents) :
418 super_type(base,extents) {
419 boost::function_requires<
420 detail::multi_array::CollectionConcept<ExtentList> >();
423 template <class ExtentList>
424 explicit multi_array_ref(T* base, const ExtentList& extents,
425 const general_storage_order<NumDims>& so) :
426 super_type(base,extents,so) {
427 boost::function_requires<
428 detail::multi_array::CollectionConcept<ExtentList> >();
432 explicit multi_array_ref(T* base,
433 const detail::multi_array::
434 extent_gen<NumDims>& ranges) :
435 super_type(base,ranges) { }
438 explicit multi_array_ref(T* base,
439 const detail::multi_array::
442 const general_storage_order<NumDims>& so) :
443 super_type(base,ranges,so) { }
445 template <typename OPtr>
446 multi_array_ref(const detail::multi_array::
447 const_sub_array<T,NumDims,OPtr>& rhs)
450 // Assignment from other ConstMultiArray types.
451 template <typename ConstMultiArray>
452 multi_array_ref& operator=(const ConstMultiArray& other) {
454 detail::multi_array::
455 ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
457 // make sure the dimensions agree
458 assert(other.num_dimensions() == num_dimensions());
459 assert(std::equal(other.shape(),other.shape()+num_dimensions(),
461 // iterator-based copy
462 std::copy(other.begin(),other.end(),begin());
466 multi_array_ref& operator=(const multi_array_ref& other) {
467 if (&other != this) {
468 // make sure the dimensions agree
470 assert(other.num_dimensions() == num_dimensions());
471 assert(std::equal(other.shape(),other.shape()+num_dimensions(),
473 // iterator-based copy
474 std::copy(other.begin(),other.end(),begin());
479 element* origin() { return base_+origin_offset_; }
481 element* data() { return base_; }
483 template <class IndexList>
484 element& operator()(const IndexList& indices) {
485 boost::function_requires<
486 detail::multi_array::CollectionConcept<IndexList> >();
487 return super_type::access_element(boost::type<element&>(),
493 reference operator[](index idx) {
494 return super_type::access(boost::type<reference>(),
501 // See note attached to generate_array_view in base.hpp
502 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
505 template <int NumDims, int NDims> // else ICE
507 typename array_view<NDims>::type
508 operator[](const detail::multi_array::
509 index_gen<NumDims,NDims>& indices) {
510 typedef typename array_view<NDims>::type return_type;
512 super_type::generate_array_view(boost::type<return_type>(),
522 return iterator(iter_base(*index_bases(),origin(),shape(),
523 strides(),index_bases()));
527 return iterator(iter_base(*index_bases()+*shape(),origin(),
528 shape(),strides(),index_bases()));
531 // RG - rbegin() and rend() written naively to thwart MSVC ICE.
532 reverse_iterator rbegin() {
533 reverse_iterator ri(end());
537 reverse_iterator rend() {
538 reverse_iterator ri(begin());
542 // Using declarations don't seem to work for g++
543 // These are the proxies to work around this.
545 const element* origin() const { return super_type::origin(); }
546 const element* data() const { return super_type::data(); }
548 template <class IndexList>
549 const element& operator()(const IndexList& indices) const {
550 boost::function_requires<
551 detail::multi_array::CollectionConcept<IndexList> >();
552 return super_type::operator()(indices);
555 const_reference operator[](index idx) const {
556 return super_type::access(boost::type<const_reference>(),
558 shape(),strides(),index_bases());
561 // See note attached to generate_array_view in base.hpp
562 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
565 template <int NumDims, int NDims> // else ICE
567 typename const_array_view<NDims>::type
568 operator[](const detail::multi_array::
569 index_gen<NumDims,NDims>& indices)
571 return super_type::operator[](indices);
574 const_iterator begin() const {
575 return super_type::begin();
578 const_iterator end() const {
579 return super_type::end();
582 const_reverse_iterator rbegin() const {
583 return super_type::rbegin();
586 const_reverse_iterator rend() const {
587 return super_type::rend();
593 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP