source: NonGTP/Boost/boost/multi_array/multi_array_ref.hpp @ 857

Revision 857, 20.1 KB checked in by igarcia, 18 years ago (diff)
Line 
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/array.hpp"
29#include "boost/concept_check.hpp"
30#include "boost/functional.hpp"
31#include "boost/limits.hpp"
32#include <algorithm>
33#include <cassert>
34#include <cstddef>
35#include <functional>
36#include <numeric>
37
38namespace boost {
39
40template <typename T, std::size_t NumDims,
41  typename TPtr = const T*
42>
43class const_multi_array_ref :
44    public detail::multi_array::multi_array_impl_base<T,NumDims>
45{
46  typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type;
47public:
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;
58
59  // template typedefs
60  template <std::size_t NDims>
61  struct const_array_view {
62    typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
63  };
64
65  template <std::size_t NDims>
66  struct array_view {
67    typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
68  };
69
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;
74#endif
75
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_)  {  }
87
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> >();
93
94    index_base_list_.assign(0);
95    init_multi_array_ref(extents.begin());
96  }
97 
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> >();
104
105    index_base_list_.assign(0);
106    init_multi_array_ref(extents.begin());
107  }
108 
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()) {
113
114    init_from_extent_gen(ranges);
115  }
116 
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) {
122
123    init_from_extent_gen(ranges);
124  }
125 
126  template <class InputIterator>
127  void assign(InputIterator begin, InputIterator end) {
128    boost::function_requires<InputIteratorConcept<InputIterator> >();
129
130    InputIterator in_iter = begin;
131    T* out_iter = base_;
132    std::size_t copy_count=0;
133    while (in_iter != end && copy_count < num_elements_) {
134      *out_iter++ = *in_iter++;
135      copy_count++;     
136    }
137  }
138
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());
145    origin_offset_ =
146      this->calculate_origin_offset(stride_list_,extent_list_,
147                              storage_,index_base_list_);
148  }
149
150  void reindex(index value) {
151    index_base_list_.assign(value);
152    origin_offset_ =
153      this->calculate_origin_offset(stride_list_,extent_list_,
154                              storage_,index_base_list_);
155  }
156
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>()));
164
165    std::copy(extents.begin(),extents.end(),extent_list_.begin());
166    this->compute_strides(stride_list_,extent_list_,storage_);
167
168    origin_offset_ =
169      this->calculate_origin_offset(stride_list_,extent_list_,
170                              storage_,index_base_list_);
171  }
172
173  size_type num_dimensions() const { return NumDims; }
174
175  size_type size() const { return extent_list_.front(); }
176
177  // given reshaping functionality, this is the max possible size.
178  size_type max_size() const { return num_elements(); }
179
180  bool empty() const { return size() == 0; }
181
182  const size_type* shape() const {
183    return extent_list_.data();
184  }
185
186  const index* strides() const {
187    return stride_list_.data();
188  }
189
190  const element* origin() const { return base_+origin_offset_; }
191  const element* data() const { return base_; }
192
193  size_type num_elements() const { return num_elements_; }
194
195  const index* index_bases() const {
196    return index_base_list_.data();
197  }
198
199
200  const storage_order_type& storage_order() const {
201    return storage_;
202  }
203
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&>(),
209                                      origin(),
210                                      indices,strides());
211  }
212
213  // Only allow const element access
214  const_reference operator[](index idx) const {
215    return super_type::access(boost::type<const_reference>(),
216                              idx,origin(),
217                              shape(),strides(),index_bases());
218  }
219
220  // see generate_array_view in base.hpp
221#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
222  template <int NDims>
223#else
224  template <int NumDims, int NDims> // else ICE
225#endif // BOOST_MSVC
226  typename const_array_view<NDims>::type
227  operator[](const detail::multi_array::
228             index_gen<NumDims,NDims>& indices)
229    const {
230    typedef typename const_array_view<NDims>::type return_type;
231    return
232      super_type::generate_array_view(boost::type<return_type>(),
233                                      indices,
234                                      shape(),
235                                      strides(),
236                                      index_bases(),
237                                      origin());
238  }
239 
240  const_iterator begin() const {
241    return const_iterator(*index_bases(),origin(),
242                          shape(),strides(),index_bases());
243  }
244
245  const_iterator end() const {
246    return const_iterator(*index_bases()+(index)*shape(),origin(),
247                          shape(),strides(),index_bases());
248  }
249
250  const_reverse_iterator rbegin() const {
251    return const_reverse_iterator(end());
252  }
253
254  const_reverse_iterator rend() const {
255    return const_reverse_iterator(begin());
256  }
257
258
259  template <typename OPtr>
260  bool operator==(const
261                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
262    const {
263    if(std::equal(extent_list_.begin(),
264                  extent_list_.end(),
265                  rhs.extent_list_.begin()))
266      return std::equal(begin(),end(),rhs.begin());
267    else return false;
268  }
269
270  template <typename OPtr>
271  bool operator<(const
272                 const_multi_array_ref<T,NumDims,OPtr>& rhs)
273    const {
274    return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
275  }
276
277  template <typename OPtr>
278  bool operator!=(const
279                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
280    const {
281    return !(*this == rhs);
282  }
283
284  template <typename OPtr>
285  bool operator>(const
286                 const_multi_array_ref<T,NumDims,OPtr>& rhs)
287    const {
288    return rhs < *this;
289  }
290
291  template <typename OPtr>
292  bool operator<=(const
293                 const_multi_array_ref<T,NumDims,OPtr>& rhs)
294    const {
295    return !(*this > rhs);
296  }
297
298  template <typename OPtr>
299  bool operator>=(const
300                 const_multi_array_ref<T,NumDims,OPtr>& rhs)
301    const {
302    return !(*this < rhs);
303  }
304
305
306#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
307protected:
308#else
309public:
310#endif
311
312  typedef boost::array<size_type,NumDims> size_list;
313  typedef boost::array<index,NumDims> index_list;
314
315  // This is used by multi_array, which is a subclass of this
316  void set_base_ptr(TPtr new_base) { base_ = new_base; }
317
318
319  // This constructor supports multi_array's default constructor
320  // and constructors from multi_array_ref, subarray, and array_view
321  explicit
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)
327 {
328   // If index_bases or extents is null, then initialize the corresponding
329   // private data to zeroed lists.
330   if(index_bases) {
331     boost::detail::multi_array::
332       copy_n(index_bases,NumDims,index_base_list_.begin());
333   } else {
334     std::fill_n(index_base_list_.begin(),NumDims,0);
335   }
336   if(extents) {
337     init_multi_array_ref(extents);
338   } else {
339     boost::array<index,NumDims> extent_list;
340     extent_list.assign(0);
341     init_multi_array_ref(extent_list.begin());
342   }
343 }
344
345
346  TPtr base_;
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_;
354
355private:
356  // const_multi_array_ref cannot be assigned to (no deep copies!)
357  const_multi_array_ref& operator=(const const_multi_array_ref& other);
358
359  void init_from_extent_gen(const
360                        detail::multi_array::
361                        extent_gen<NumDims>& ranges) {
362   
363    typedef boost::array<index,NumDims> extent_list;
364
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));
369
370    // calculate the extents
371    extent_list extents;
372    std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
373              extents.begin(),
374              boost::mem_fun_ref(&extent_range::size));
375
376    init_multi_array_ref(extents.begin());
377  }
378
379
380#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
381protected:
382#else
383public:
384#endif
385  // RG - move me!
386  template <class InputIterator>
387  void init_multi_array_ref(InputIterator extents_iter) {
388    boost::function_requires<InputIteratorConcept<InputIterator> >();
389
390    boost::detail::multi_array::
391      copy_n(extents_iter,num_dimensions(),extent_list_.begin());
392
393    // Calculate the array size
394    num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
395                            size_type(1),std::multiplies<size_type>());
396
397    this->compute_strides(stride_list_,extent_list_,storage_);
398
399    origin_offset_ =
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_,
404                                            storage_);
405  }
406};
407
408template <typename T, std::size_t NumDims>
409class multi_array_ref :
410  public const_multi_array_ref<T,NumDims,T*>
411{
412  typedef const_multi_array_ref<T,NumDims,T*> super_type;
413public:
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;
426
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;
430
431  template <std::size_t NDims>
432  struct const_array_view {
433    typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
434  };
435
436  template <std::size_t NDims>
437  struct array_view {
438    typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
439  };
440
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> >();
446  }
447
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> >();
454  }
455
456
457  explicit multi_array_ref(T* base,
458                           const detail::multi_array::
459                           extent_gen<NumDims>& ranges) :
460    super_type(base,ranges) { }
461
462
463  explicit multi_array_ref(T* base,
464                           const detail::multi_array::
465                           extent_gen<NumDims>&
466                             ranges,
467                           const general_storage_order<NumDims>& so) :
468    super_type(base,ranges,so) { }
469
470
471  // Assignment from other ConstMultiArray types.
472  template <typename ConstMultiArray>
473  multi_array_ref& operator=(const ConstMultiArray& other) {
474    function_requires<
475      detail::multi_array::
476      ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
477
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(),
481                      this->shape()));
482    // iterator-based copy
483    std::copy(other.begin(),other.end(),this->begin());
484    return *this;
485  }
486
487  multi_array_ref& operator=(const multi_array_ref& other) {
488    if (&other != this) {
489      // make sure the dimensions agree
490     
491      assert(other.num_dimensions() == this->num_dimensions());
492      assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
493                        this->shape()));
494      // iterator-based copy
495      std::copy(other.begin(),other.end(),this->begin());
496    }
497    return *this;
498  }
499
500  element* origin() { return super_type::base_+super_type::origin_offset_; }
501
502  element* data() { return super_type::base_; }
503
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&>(),
509                                      origin(),
510                                      indices,this->strides());
511  }
512
513
514  reference operator[](index idx) {
515    return super_type::access(boost::type<reference>(),
516                              idx,origin(),
517                              this->shape(),this->strides(),
518                              this->index_bases());
519  }
520
521
522  // See note attached to generate_array_view in base.hpp
523#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
524  template <int NDims>
525#else
526  template <int NumDims, int NDims> // else ICE
527#endif // BOOST_MSVC
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;
532    return
533      super_type::generate_array_view(boost::type<return_type>(),
534                                      indices,
535                                      this->shape(),
536                                      this->strides(),
537                                      this->index_bases(),
538                                      origin());
539  }
540 
541 
542  iterator begin() {
543    return iterator(*this->index_bases(),origin(),this->shape(),
544                    this->strides(),this->index_bases());
545  }
546
547  iterator end() {
548    return iterator(*this->index_bases()+(index)*this->shape(),origin(),
549                    this->shape(),this->strides(),
550                    this->index_bases());
551  }
552
553  // rbegin() and rend() written naively to thwart MSVC ICE.
554  reverse_iterator rbegin() {
555    reverse_iterator ri(end());
556    return ri;
557  }
558
559  reverse_iterator rend() {
560    reverse_iterator ri(begin());
561    return ri;
562  }
563
564  // Using declarations don't seem to work for g++
565  // These are the proxies to work around this.
566
567  const element* origin() const { return super_type::origin(); }
568  const element* data() const { return super_type::data(); }
569
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);
575  }
576
577  const_reference operator[](index idx) const {
578    return super_type::access(boost::type<const_reference>(),
579                              idx,origin(),
580                              this->shape(),this->strides(),
581                              this->index_bases());
582  }
583
584  // See note attached to generate_array_view in base.hpp
585#if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
586  template <int NDims>
587#else
588  template <int NumDims, int NDims> // else ICE
589#endif // BOOST_MSVC
590  typename const_array_view<NDims>::type
591  operator[](const detail::multi_array::
592             index_gen<NumDims,NDims>& indices)
593    const {
594    return super_type::operator[](indices);
595  }
596 
597  const_iterator begin() const {
598    return super_type::begin();
599  }
600
601  const_iterator end() const {
602    return super_type::end();
603  }
604
605  const_reverse_iterator rbegin() const {
606    return super_type::rbegin();
607  }
608
609  const_reverse_iterator rend() const {
610    return super_type::rend();
611  }
612
613protected:
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) { }
620
621};
622
623} // namespace boost
624
625#endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP
Note: See TracBrowser for help on using the repository browser.