]> git.lyx.org Git - lyx.git/blob - boost/boost/multi_array/base.hpp
2002-05-24 Lars Gullik Bj�nnes <larsbj@birdstep.com>
[lyx.git] / boost / boost / multi_array / base.hpp
1 #ifndef BASE_RG071801_HPP
2 #define BASE_RG071801_HPP
3
4 //
5 // base.hpp - some implementation base classes for from which
6 // functionality is acquired
7 //
8
9 #include "boost/multi_array/extent_range.hpp"
10 #include "boost/multi_array/extent_gen.hpp"
11 #include "boost/multi_array/index_range.hpp"
12 #include "boost/multi_array/index_gen.hpp"
13 #include "boost/multi_array/storage_order.hpp"
14 #include "boost/multi_array/types.hpp"
15 #include "boost/config.hpp"
16 #include "boost/multi_array/iterator_adaptors.hpp"
17 #include "boost/static_assert.hpp"
18 #include "boost/type.hpp"
19 #include <cassert>
20 #include <cstddef>
21 #include <memory>
22
23 namespace boost {
24
25 /////////////////////////////////////////////////////////////////////////
26 // class declarations
27 /////////////////////////////////////////////////////////////////////////
28
29 template<typename T, std::size_t NumDims,
30   typename Allocator = std::allocator<T> >
31 class multi_array;
32
33 // This is a public interface for use by end users!
34 namespace multi_array_types {
35   typedef boost::detail::multi_array::size_type size_type;
36   typedef std::ptrdiff_t difference_type;
37   typedef boost::detail::multi_array::index index;
38   typedef detail::multi_array::index_range<index,size_type> index_range;
39   typedef detail::multi_array::extent_range<index,size_type> extent_range;
40   typedef detail::multi_array::index_gen<0,0> index_gen;
41   typedef detail::multi_array::extent_gen<0> extent_gen;
42 }
43
44
45 // boost::extents and boost::indices are now a part of the public
46 // interface.  That way users don't necessarily have to create their 
47 // own objects.  On the other hand, one may not want the overhead of 
48 // object creation in small-memory environments.  Thus, the objects
49 // can be left undefined by defining BOOST_MULTI_ARRAY_NO_GENERATORS 
50 // before loading multi_array.hpp.
51 #if !BOOST_MULTI_ARRAY_NO_GENERATORS
52 namespace {
53   multi_array_types::extent_gen extents;
54   multi_array_types::index_gen indices;
55 }
56 #endif // BOOST_MULTI_ARRAY_NO_GENERATORS
57
58 namespace detail {
59 namespace multi_array {
60
61 template <typename T, std::size_t NumDims>
62 class sub_array;
63
64 template <typename T, std::size_t NumDims, typename TPtr = const T*>
65 class const_sub_array;
66
67 template <typename T, std::size_t NumDims, typename value_type,
68   typename reference_type, typename tag, typename difference_type>
69 struct iterator_generator;
70
71 template <typename T, std::size_t NumDims, typename value_type,
72   typename reference_type, typename tag, typename difference_type>
73 struct const_iterator_generator;
74
75 template <typename T, std::size_t NumDims, typename value_type,
76   typename reference_type, typename tag, typename difference_type>
77 struct reverse_iterator_generator;
78
79 template <typename T, std::size_t NumDims, typename value_type,
80   typename reference_type, typename tag, typename difference_type>
81 struct const_reverse_iterator_generator;
82
83 template <typename T,typename TPtr>
84 struct iterator_base;
85
86 template <typename T, std::size_t NumDims>
87 struct iterator_policies;
88
89 template <typename T, std::size_t NumDims, typename TPtr = const T*>
90 class const_multi_array_view;
91
92 template <typename T, std::size_t NumDims>
93 class multi_array_view;
94
95 /////////////////////////////////////////////////////////////////////////
96 // class interfaces
97 /////////////////////////////////////////////////////////////////////////
98
99 class multi_array_base {
100 public:
101   typedef multi_array_types::size_type size_type;
102   typedef multi_array_types::difference_type difference_type;
103   typedef multi_array_types::index index;
104   typedef multi_array_types::index_range index_range;
105   typedef multi_array_types::extent_range extent_range;
106   typedef multi_array_types::index_gen index_gen;
107   typedef multi_array_types::extent_gen extent_gen;
108 };
109
110 //
111 // value_accessor_n
112 //  contains the routines for accessing elements from
113 //  N-dimensional views.
114 //
115 template<typename T, std::size_t NumDims>
116 class value_accessor_n : public multi_array_base {
117   typedef multi_array_base super_type;
118 public:
119   typedef typename super_type::index index;
120
121   // 
122   // public typedefs used by classes that inherit from this base
123   //
124   typedef T element;
125   typedef boost::multi_array<T,NumDims-1> value_type;
126   typedef sub_array<T,NumDims-1> reference;
127   typedef const_sub_array<T,NumDims-1> const_reference;
128
129 protected:
130   // used by array operator[] and iterators to get reference types.
131   template <typename Reference, typename TPtr>
132   Reference access(boost::type<Reference>,index idx,TPtr base,
133                    const size_type* extents,
134                    const index* strides,
135                    const index* index_base) const {
136
137     // return a sub_array<T,NDims-1> proxy object
138     TPtr newbase = base + idx * strides[0];
139     return Reference(newbase,extents+1,strides+1,index_base+1);
140
141   }
142
143   value_accessor_n() { }
144   ~value_accessor_n() { }
145 };
146
147
148
149 //
150 // value_accessor_one
151 //  contains the routines for accessing reference elements from
152 //  1-dimensional views.
153 //
154 template<typename T>
155 class value_accessor_one : public multi_array_base {
156   typedef multi_array_base super_type;
157 public:
158   typedef typename super_type::index index;
159   //
160   // public typedefs for use by classes that inherit it.
161   //
162   typedef T element;
163   typedef T value_type;
164   typedef T& reference;
165   typedef T const& const_reference;
166
167 protected:
168   // used by array operator[] and iterators to get reference types.
169   template <typename Reference, typename TPtr>
170   Reference access(boost::type<Reference>,index idx,TPtr base,
171                    const size_type*,
172                    const index* strides,
173                    const index*) const {
174     return *(base + idx * strides[0]);
175   }
176
177   value_accessor_one() { }
178   ~value_accessor_one() { }
179 };
180
181
182 /////////////////////////////////////////////////////////////////////////
183 // choose value accessor begins
184 //
185
186 struct choose_value_accessor_n {
187   template <typename T, std::size_t NumDims>
188   struct bind {
189     typedef value_accessor_n<T,NumDims> type;
190   };
191 };
192
193 struct choose_value_accessor_one {
194   template <typename T, std::size_t NumDims>
195   struct bind {
196     typedef value_accessor_one<T> type;
197   };
198 };
199
200
201 template <std::size_t NumDims>
202 struct value_accessor_gen_helper {
203   typedef choose_value_accessor_n choice;
204 };
205
206 template <>
207 struct value_accessor_gen_helper<1> {
208   typedef choose_value_accessor_one choice;
209 };
210
211 template <typename T, std::size_t NumDims>
212 struct value_accessor_generator {
213 private:
214   typedef typename value_accessor_gen_helper<NumDims>::choice Choice;
215 public:
216   typedef typename Choice::template bind<T,NumDims>::type type;
217 };
218
219 //
220 // choose value accessor ends
221 /////////////////////////////////////////////////////////////////////////
222
223
224 /////////////////////////////////////////////////////////////////////////
225 // multi_array/sub_array base stuffs
226 /////////////////////////////////////////////////////////////////////////
227 template <std::size_t NumDims>
228 struct iterator_tag_selector {
229   typedef std::input_iterator_tag type;
230 };
231
232 template <>
233 struct iterator_tag_selector<1> {
234   typedef std::random_access_iterator_tag type;
235 };
236
237
238 ////////////////////////////////////////////////////////////////////////
239 // multi_array_base
240 ////////////////////////////////////////////////////////////////////////
241 template <typename T, std::size_t NumDims>
242 class multi_array_impl_base :
243   public value_accessor_generator<T,NumDims>::type {
244   typedef typename value_accessor_generator<T,NumDims>::type super_type;
245 public:
246   typedef typename super_type::index index;
247   typedef typename super_type::size_type size_type;
248   typedef typename super_type::element element;
249   typedef typename super_type::index_range index_range;
250   typedef typename super_type::value_type value_type;
251   typedef typename super_type::reference reference;
252   typedef typename super_type::const_reference const_reference;
253
254   template <std::size_t NDims>
255   struct subarray {
256     typedef boost::detail::multi_array::sub_array<T,NDims> type;
257   };
258
259   template <std::size_t NDims>
260   struct const_subarray {
261     typedef boost::detail::multi_array::const_sub_array<T,NDims> type;
262   };
263
264   template <std::size_t NDims>
265   struct array_view {
266     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
267   };
268
269   template <std::size_t NDims>
270   struct const_array_view {
271   public:
272     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
273   };
274
275   //
276   // iterator support
277   //
278
279   typedef typename iterator_tag_selector<NumDims>::type iterator_tag;
280
281   typedef typename
282     iterator_generator<T,NumDims,value_type,
283     reference,iterator_tag,index>::type iterator;
284
285   typedef typename
286     const_iterator_generator<T,NumDims,value_type,
287     const_reference,iterator_tag,index>::type const_iterator;
288
289   typedef typename
290     reverse_iterator_generator<T,NumDims,value_type,
291     reference,iterator_tag,index>::type reverse_iterator;
292
293   typedef typename
294     const_reverse_iterator_generator<T,NumDims,value_type,
295     const_reference,iterator_tag,index>::type const_reverse_iterator;
296
297 protected:
298   typedef iterator_base<T,T*> iter_base;
299   typedef iterator_base<T,const T*> const_iter_base;
300
301   multi_array_impl_base() { }
302   ~multi_array_impl_base() { }
303
304   // Used by operator() in our array classes
305   template <typename Reference, typename IndexList, typename TPtr>
306   Reference access_element(boost::type<Reference>, TPtr base,
307                            const IndexList& indices,
308                            const index* strides) const {
309     index offset = 0;
310     for (size_type n = 0; n != NumDims; ++n) 
311       offset += indices[n] * strides[n];
312     
313     return base[offset];
314   }
315
316   template <typename StrideList, typename ExtentList>
317   void compute_strides(StrideList& stride_list, ExtentList& extent_list,
318                        const general_storage_order<NumDims>& storage)
319   {
320     // invariant: stride = the stride for dimension n
321     index stride = 1;
322     for (size_type n = 0; n != NumDims; ++n) {
323       index stride_sign = +1;
324       
325       if (!storage.ascending(storage.ordering(n)))
326         stride_sign = -1;
327       
328       // The stride for this dimension is the product of the
329       // lengths of the ranks minor to it.
330       stride_list[storage.ordering(n)] = stride * stride_sign;
331       
332       stride *= extent_list[storage.ordering(n)];
333     } 
334   }
335
336   // This calculates the offset to the array base pointer due to:
337   // 1. dimensions stored in descending order
338   // 2. non-zero dimension index bases
339   template <typename StrideList, typename ExtentList, typename BaseList>
340   index
341   calculate_origin_offset(const StrideList& stride_list,
342                           const ExtentList& extent_list,
343                           const general_storage_order<NumDims>& storage,
344                           const BaseList& index_base_list)
345   {
346     return
347       calculate_descending_dimension_offset(stride_list,extent_list,
348                                             storage) +
349       calculate_indexing_offset(stride_list,index_base_list);
350   }
351
352   // This calculates the offset added to the base pointer that are
353   // caused by descending dimensions
354   template <typename StrideList, typename ExtentList>
355   index
356   calculate_descending_dimension_offset(const StrideList& stride_list,
357                                 const ExtentList& extent_list,
358                                 const general_storage_order<NumDims>& storage)
359   {
360     index offset = 0;
361     if (!storage.all_dims_ascending()) 
362       for (size_type n = 0; n != NumDims; ++n)
363         if (!storage.ascending(n))
364           offset -= (extent_list[n] - 1) * stride_list[n];
365
366     return offset;
367   }
368
369   // This is used to reindex array_views, which are no longer
370   // concerned about storage order (specifically, whether dimensions
371   // are ascending or descending) since the viewed array handled it.
372
373   template <typename StrideList, typename BaseList>
374   index
375   calculate_indexing_offset(const StrideList& stride_list,
376                           const BaseList& index_base_list)
377   {
378     index offset = 0;
379     for (size_type n = 0; n != NumDims; ++n)
380         offset -= stride_list[n] * index_base_list[n];
381     return offset;
382   }
383
384   // Slicing using an index_gen.
385   // Note that populating an index_gen creates a type that encodes
386   // both the number of dimensions in the current Array (NumDims), and 
387   // the Number of dimensions for the resulting view.  This allows the 
388   // compiler to fail if the dimensions aren't completely accounted
389   // for.  For reasons unbeknownst to me, a BOOST_STATIC_ASSERT
390   // within the member function template does not work. I should add a 
391   // note to the documentation specifying that you get a damn ugly
392   // error message if you screw up in your slicing code.
393   template <typename ArrayRef, int NDims, typename TPtr>
394   ArrayRef
395   generate_array_view(boost::type<ArrayRef>,
396                       const boost::detail::multi_array::
397                       index_gen<NumDims,NDims>& indices,
398                       const size_type* extents,
399                       const index* strides,
400                       const index* index_bases,
401                       TPtr base) const {
402
403     boost::array<index,NDims> new_strides;
404     boost::array<index,NDims> new_extents;
405
406     index offset = 0;
407     size_type dim = 0;
408     for (size_type n = 0; n != NumDims; ++n) {
409       const index default_start = index_bases[n];
410       const index default_finish = default_start+extents[n];
411       const index_range& current_range = indices.ranges_[n];
412       index start = current_range.get_start(default_start);
413       index finish = current_range.get_finish(default_finish);
414       index index_factor = current_range.stride();
415       index len = (finish - start) / index_factor;
416
417       // the array data pointer is modified to account for non-zero
418       // bases during slicing (see [Garcia] for the math involved)
419       offset += start * strides[n];
420
421       if (!current_range.is_degenerate()) {
422
423         // The index_factor for each dimension is included into the
424         // strides for the array_view (see [Garcia] for the math involved).
425         new_strides[dim] = index_factor * strides[n];
426         
427         // calculate new extents
428         new_extents[dim] = len;
429         ++dim;
430       }
431     }
432     assert (dim == NDims);
433
434     return
435       ArrayRef(base+offset,
436                new_extents,
437                new_strides);
438   }
439                      
440
441 };
442
443 } // namespace multi_array
444 } // namespace detail
445
446 } // namespace boost
447
448 #endif // BASE_RG071801_HPP