]> git.lyx.org Git - lyx.git/blob - boost/boost/multi_array/multi_array_ref.hpp
Boost 1.31.0
[lyx.git] / boost / boost / multi_array / multi_array_ref.hpp
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
38 namespace boost {
39
40 template <typename T, std::size_t NumDims,
41   typename TPtr = const T*
42 >
43 class 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;
47 public: 
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
75 //  template <typename From, typename To>  // needed for enable_if_convertible tests
76 //  friend class boost::detail::is_convertible_basic_impl;
77 #endif
78
79   template <typename OPtr>
80   const_multi_array_ref(const const_multi_array_ref<T,NumDims,
81                         OPtr>& other)
82     : base_(other.base_), storage_(other.storage_),
83       extent_list_(other.extent_list_),
84       stride_list_(other.stride_list_),
85       index_base_list_(other.index_base_list_),
86       origin_offset_(other.origin_offset_),
87       directional_offset_(other.directional_offset_),
88       num_elements_(other.num_elements_)  {  }
89
90   template <typename ExtentList>
91   explicit const_multi_array_ref(TPtr base, const ExtentList& extents) :
92     base_(base), storage_(c_storage_order()) {
93     boost::function_requires<
94       detail::multi_array::CollectionConcept<ExtentList> >();
95
96     index_base_list_.assign(0);
97     init_multi_array_ref(extents.begin());
98   }
99   
100   template <typename ExtentList>
101   explicit const_multi_array_ref(TPtr base, const ExtentList& extents,
102                        const general_storage_order<NumDims>& so) : 
103     base_(base), storage_(so) {
104     boost::function_requires<
105       detail::multi_array::CollectionConcept<ExtentList> >();
106
107     index_base_list_.assign(0);
108     init_multi_array_ref(extents.begin());
109   }
110   
111   explicit const_multi_array_ref(TPtr base,
112                          const detail::multi_array::
113                          extent_gen<NumDims>& ranges) :
114     base_(base), storage_(c_storage_order()) {
115
116     init_from_extent_gen(ranges);
117   }
118   
119   explicit const_multi_array_ref(TPtr base,
120                            const detail::multi_array::
121                            extent_gen<NumDims>& ranges,
122                            const general_storage_order<NumDims>& so) :
123     base_(base), storage_(so) {
124
125     init_from_extent_gen(ranges);
126   }
127   
128   template <class InputIterator>
129   void assign(InputIterator begin, InputIterator end) {
130     boost::function_requires<InputIteratorConcept<InputIterator> >();
131
132     InputIterator in_iter = begin;
133     T* out_iter = base_;
134     std::size_t copy_count=0;
135     while (in_iter != end && copy_count < num_elements_) {
136       *out_iter++ = *in_iter++;
137       copy_count++;      
138     }
139   }
140
141   template <class BaseList>
142   void reindex(const BaseList& values) {
143     boost::function_requires<
144       detail::multi_array::CollectionConcept<BaseList> >();
145     boost::copy_n(values.begin(),num_dimensions(),index_base_list_.begin());
146     origin_offset_ =
147       this->calculate_origin_offset(stride_list_,extent_list_,
148                               storage_,index_base_list_);
149   }
150
151   void reindex(index value) {
152     index_base_list_.assign(value);
153     origin_offset_ =
154       this->calculate_origin_offset(stride_list_,extent_list_,
155                               storage_,index_base_list_);
156   }
157
158   template <typename SizeList>
159   void reshape(const SizeList& extents) {
160     boost::function_requires<
161       detail::multi_array::CollectionConcept<SizeList> >();
162     assert(num_elements_ ==
163            std::accumulate(extents.begin(),extents.end(),
164                             size_type(1),std::multiplies<size_type>()));
165
166     std::copy(extents.begin(),extents.end(),extent_list_.begin());
167     this->compute_strides(stride_list_,extent_list_,storage_);
168
169     origin_offset_ =
170       this->calculate_origin_offset(stride_list_,extent_list_,
171                               storage_,index_base_list_);
172   }
173
174   size_type num_dimensions() const { return NumDims; }
175
176   size_type size() const { return extent_list_.front(); }
177
178   // given reshaping functionality, this is the max possible size.
179   size_type max_size() const { return num_elements(); }
180
181   bool empty() const { return size() == 0; }
182
183   const size_type* shape() const {
184     return extent_list_.data();
185   }
186
187   const index* strides() const {
188     return stride_list_.data();
189   }
190
191   const element* origin() const { return base_+origin_offset_; }
192   const element* data() const { return base_; }
193
194   size_type num_elements() const { return num_elements_; }
195
196   const index* index_bases() const {
197     return index_base_list_.data();
198   }
199
200
201   const storage_order_type& storage_order() const {
202     return storage_;
203   }
204
205   template <typename IndexList>
206   const element& operator()(IndexList indices) const {
207     boost::function_requires<
208       detail::multi_array::CollectionConcept<IndexList> >();
209     return super_type::access_element(boost::type<const element&>(),
210                                       origin(),
211                                       indices,strides());
212   }
213
214   // Only allow const element access
215   const_reference operator[](index idx) const {
216     return super_type::access(boost::type<const_reference>(),
217                               idx,origin(),
218                               shape(),strides(),index_bases());
219   }
220
221   // see generate_array_view in base.hpp
222 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
223   template <int NDims>
224 #else
225   template <int NumDims, int NDims> // else ICE
226 #endif // BOOST_MSVC
227   typename const_array_view<NDims>::type 
228   operator[](const detail::multi_array::
229              index_gen<NumDims,NDims>& indices)
230     const {
231     typedef typename const_array_view<NDims>::type return_type;
232     return
233       super_type::generate_array_view(boost::type<return_type>(),
234                                       indices,
235                                       shape(),
236                                       strides(),
237                                       index_bases(),
238                                       origin());
239   }
240   
241   const_iterator begin() const {
242     return const_iterator(*index_bases(),origin(),
243                           shape(),strides(),index_bases());
244   }
245
246   const_iterator end() const {
247     return const_iterator(*index_bases()+*shape(),origin(),
248                           shape(),strides(),index_bases());
249   }
250
251   const_reverse_iterator rbegin() const {
252     return const_reverse_iterator(end());
253   }
254
255   const_reverse_iterator rend() const {
256     return const_reverse_iterator(begin());
257   }
258
259
260   template <typename OPtr>
261   bool operator==(const
262                   const_multi_array_ref<T,NumDims,OPtr>& rhs)
263     const {
264     if(std::equal(extent_list_.begin(),
265                   extent_list_.end(),
266                   rhs.extent_list_.begin()))
267       return std::equal(begin(),end(),rhs.begin());
268     else return false;
269   }
270
271   template <typename OPtr>
272   bool operator<(const
273                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
274     const {
275     return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end());
276   }
277
278   template <typename OPtr>
279   bool operator!=(const
280                   const_multi_array_ref<T,NumDims,OPtr>& rhs)
281     const {
282     return !(*this == rhs);
283   }
284
285   template <typename OPtr>
286   bool operator>(const
287                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
288     const {
289     return rhs < *this;
290   }
291
292   template <typename OPtr>
293   bool operator<=(const
294                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
295     const {
296     return !(*this > rhs);
297   }
298
299   template <typename OPtr>
300   bool operator>=(const
301                  const_multi_array_ref<T,NumDims,OPtr>& rhs)
302     const {
303     return !(*this < rhs);
304   }
305
306 protected:
307   // This is only supplied to support multi_array's default constructor
308   explicit const_multi_array_ref(TPtr base) :
309     base_(base), storage_(c_storage_order()) {
310     index_base_list_.assign(0);
311     boost::array<size_type,NumDims> filler;
312     filler.assign(0);
313     init_multi_array_ref(filler.begin());
314   }
315
316
317 // This ensures that const_multi_array_ref types with different TPtr 
318 // types can convert to each other
319 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
320 protected:
321 #else
322 public:
323 #endif
324   // This is used by multi_array, which is a subclass of this
325   void set_base_ptr(TPtr new_base) { base_ = new_base; }
326
327   template <typename OPtr>
328   const_multi_array_ref(
329       const detail::multi_array::const_sub_array<T,NumDims,OPtr>& rhs
330   )
331     : base_(0), // playing it "safe"; so we learn of errors
332       storage_(c_storage_order()),
333       origin_offset_(0), directional_offset_(0),
334       num_elements_(rhs.num_elements())
335   {
336     using boost::copy_n;
337     copy_n(rhs.shape(),rhs.num_dimensions(),extent_list_.begin());
338     copy_n(rhs.strides(),rhs.num_dimensions(),stride_list_.begin());
339     copy_n(rhs.index_bases(),rhs.num_dimensions(),index_base_list_.begin());
340   }
341
342   typedef boost::array<size_type,NumDims> size_list;
343   typedef boost::array<index,NumDims> index_list;
344
345   TPtr base_;
346   storage_order_type storage_;
347   size_list extent_list_;
348   index_list stride_list_;
349   index_list index_base_list_;
350   index origin_offset_;
351   index directional_offset_;
352   size_type num_elements_;
353
354 private:
355   // const_multi_array_ref cannot be assigned to (no deep copies!)
356   const_multi_array_ref& operator=(const const_multi_array_ref& other);
357
358   void init_from_extent_gen(const
359                         detail::multi_array::
360                         extent_gen<NumDims>& ranges) { 
361     
362     typedef boost::array<index,NumDims> extent_list;
363
364     // get the index_base values
365     std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
366               index_base_list_.begin(),
367               boost::mem_fun_ref(&extent_range::start));
368
369     // calculate the extents
370     extent_list extents;
371     std::transform(ranges.ranges_.begin(),ranges.ranges_.end(),
372               extents.begin(),
373               boost::mem_fun_ref(&extent_range::size));
374
375     init_multi_array_ref(extents.begin());
376   }
377
378
379   template <class InputIterator>
380   void init_multi_array_ref(InputIterator extents_iter) {
381     boost::function_requires<InputIteratorConcept<InputIterator> >();
382
383     boost::copy_n(extents_iter,num_dimensions(),extent_list_.begin());
384
385     // Calculate the array size
386     num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(),
387                             1,std::multiplies<index>());
388 #if 0
389     assert(num_elements_ != 0);
390 #endif
391     this->compute_strides(stride_list_,extent_list_,storage_);
392
393     origin_offset_ =
394       this->calculate_origin_offset(stride_list_,extent_list_,
395                               storage_,index_base_list_);
396     directional_offset_ =
397       this->calculate_descending_dimension_offset(stride_list_,extent_list_,
398                                             storage_);
399   }
400 };
401
402 template <typename T, std::size_t NumDims>
403 class multi_array_ref :
404   public const_multi_array_ref<T,NumDims,T*>
405 {
406   typedef const_multi_array_ref<T,NumDims,T*> super_type;
407 public: 
408   typedef typename super_type::value_type value_type;
409   typedef typename super_type::reference reference;
410   typedef typename super_type::iterator iterator;
411   typedef typename super_type::reverse_iterator reverse_iterator;
412   typedef typename super_type::const_reference const_reference;
413   typedef typename super_type::const_iterator const_iterator;
414   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
415   typedef typename super_type::element element;
416   typedef typename super_type::size_type size_type;
417   typedef typename super_type::difference_type difference_type;
418   typedef typename super_type::index index;
419   typedef typename super_type::extent_range extent_range;
420
421
422
423   template <std::size_t NDims>
424   struct const_array_view {
425     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
426   };
427
428   template <std::size_t NDims>
429   struct array_view {
430     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
431   };
432
433   template <class ExtentList>
434   explicit multi_array_ref(T* base, const ExtentList& extents) :
435     super_type(base,extents) {
436     boost::function_requires<
437       detail::multi_array::CollectionConcept<ExtentList> >();
438   }
439
440   template <class ExtentList>
441   explicit multi_array_ref(T* base, const ExtentList& extents,
442                            const general_storage_order<NumDims>& so) :
443     super_type(base,extents,so) {
444     boost::function_requires<
445       detail::multi_array::CollectionConcept<ExtentList> >();
446   }
447
448
449   explicit multi_array_ref(T* base,
450                            const detail::multi_array::
451                            extent_gen<NumDims>& ranges) :
452     super_type(base,ranges) { }
453
454
455   explicit multi_array_ref(T* base,
456                            const detail::multi_array::
457                            extent_gen<NumDims>&
458                              ranges,
459                            const general_storage_order<NumDims>& so) :
460     super_type(base,ranges,so) { }
461
462   template <typename OPtr>
463   multi_array_ref(const detail::multi_array::
464                   const_sub_array<T,NumDims,OPtr>& rhs)
465     : super_type(rhs) {} 
466
467   // Assignment from other ConstMultiArray types.
468   template <typename ConstMultiArray>
469   multi_array_ref& operator=(const ConstMultiArray& other) {
470     function_requires< 
471       detail::multi_array::
472       ConstMultiArrayConcept<ConstMultiArray,NumDims> >();
473
474     // make sure the dimensions agree
475     assert(other.num_dimensions() == this->num_dimensions());
476     assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
477                       this->shape()));
478     // iterator-based copy
479     std::copy(other.begin(),other.end(),this->begin());
480     return *this;
481   }
482
483   multi_array_ref& operator=(const multi_array_ref& other) {
484     if (&other != this) {
485       // make sure the dimensions agree
486       
487       assert(other.num_dimensions() == this->num_dimensions());
488       assert(std::equal(other.shape(),other.shape()+this->num_dimensions(),
489                         this->shape()));
490       // iterator-based copy
491       std::copy(other.begin(),other.end(),this->begin());
492     }
493     return *this;
494   }
495
496   element* origin() { return super_type::base_+super_type::origin_offset_; }
497
498   element* data() { return super_type::base_; }
499
500   template <class IndexList>
501   element& operator()(const IndexList& indices) {
502   boost::function_requires<
503     detail::multi_array::CollectionConcept<IndexList> >();
504   return super_type::access_element(boost::type<element&>(),
505                                       origin(),
506                                       indices,this->strides());
507   }
508
509
510   reference operator[](index idx) {
511     return super_type::access(boost::type<reference>(),
512                               idx,origin(),
513                               this->shape(),this->strides(),
514                               this->index_bases());
515   }
516
517
518   // See note attached to generate_array_view in base.hpp
519 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
520   template <int NDims>
521 #else
522   template <int NumDims, int NDims> // else ICE
523 #endif // BOOST_MSVC
524   typename array_view<NDims>::type 
525   operator[](const detail::multi_array::
526              index_gen<NumDims,NDims>& indices) {
527     typedef typename array_view<NDims>::type return_type;
528     return
529       super_type::generate_array_view(boost::type<return_type>(),
530                                       indices,
531                                       this->shape(),
532                                       this->strides(),
533                                       this->index_bases(),
534                                       origin());
535   }
536   
537   
538   iterator begin() {
539     return iterator(*this->index_bases(),origin(),this->shape(),
540                     this->strides(),this->index_bases());
541   }
542
543   iterator end() {
544     return iterator(*this->index_bases()+*this->shape(),origin(),
545                     this->shape(),this->strides(),
546                     this->index_bases());
547   }
548
549   // RG - rbegin() and rend() written naively to thwart MSVC ICE.
550   reverse_iterator rbegin() {
551     reverse_iterator ri(end());
552     return ri;
553   }
554
555   reverse_iterator rend() {
556     reverse_iterator ri(begin());
557     return ri;
558   }
559
560   // Using declarations don't seem to work for g++
561   // These are the proxies to work around this.
562
563   const element* origin() const { return super_type::origin(); }
564   const element* data() const { return super_type::data(); }
565
566   template <class IndexList>
567   const element& operator()(const IndexList& indices) const {
568     boost::function_requires<
569       detail::multi_array::CollectionConcept<IndexList> >();
570     return super_type::operator()(indices);
571   }
572
573   const_reference operator[](index idx) const {
574     return super_type::access(boost::type<const_reference>(),
575                               idx,origin(),
576                               this->shape(),this->strides(),
577                               this->index_bases());
578   }
579
580   // See note attached to generate_array_view in base.hpp
581 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
582   template <int NDims>
583 #else
584   template <int NumDims, int NDims> // else ICE
585 #endif // BOOST_MSVC
586   typename const_array_view<NDims>::type 
587   operator[](const detail::multi_array::
588              index_gen<NumDims,NDims>& indices)
589     const {
590     return super_type::operator[](indices);
591   }
592   
593   const_iterator begin() const {
594     return super_type::begin();
595   }
596
597   const_iterator end() const {
598     return super_type::end();
599   }
600
601   const_reverse_iterator rbegin() const {
602     return super_type::rbegin();
603   }
604
605   const_reverse_iterator rend() const {
606     return super_type::rend();
607   }
608
609 protected:
610   // This is only supplied to support multi_array's default constructor
611   explicit multi_array_ref(T* base) :
612     super_type(base) {
613   }
614
615
616 };
617
618 } // namespace boost
619
620 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP