1 #ifndef BASE_RG071801_HPP
2 #define BASE_RG071801_HPP
5 // base.hpp - some implementation base classes for from which
6 // functionality is acquired
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"
25 /////////////////////////////////////////////////////////////////////////
27 /////////////////////////////////////////////////////////////////////////
29 template<typename T, std::size_t NumDims,
30 typename Allocator = std::allocator<T> >
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;
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
53 multi_array_types::extent_gen extents;
54 multi_array_types::index_gen indices;
56 #endif // BOOST_MULTI_ARRAY_NO_GENERATORS
59 namespace multi_array {
61 template <typename T, std::size_t NumDims>
64 template <typename T, std::size_t NumDims, typename TPtr = const T*>
65 class const_sub_array;
67 template <typename T, std::size_t NumDims, typename value_type,
68 typename reference_type, typename tag, typename difference_type>
69 struct iterator_generator;
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;
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;
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;
83 template <typename T,typename TPtr>
86 template <typename T, std::size_t NumDims>
87 struct iterator_policies;
89 template <typename T, std::size_t NumDims, typename TPtr = const T*>
90 class const_multi_array_view;
92 template <typename T, std::size_t NumDims>
93 class multi_array_view;
95 /////////////////////////////////////////////////////////////////////////
97 /////////////////////////////////////////////////////////////////////////
99 class multi_array_base {
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;
112 // contains the routines for accessing elements from
113 // N-dimensional views.
115 template<typename T, std::size_t NumDims>
116 class value_accessor_n : public multi_array_base {
117 typedef multi_array_base super_type;
119 typedef typename super_type::index index;
122 // public typedefs used by classes that inherit from this base
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;
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 {
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);
143 value_accessor_n() { }
144 ~value_accessor_n() { }
150 // value_accessor_one
151 // contains the routines for accessing reference elements from
152 // 1-dimensional views.
155 class value_accessor_one : public multi_array_base {
156 typedef multi_array_base super_type;
158 typedef typename super_type::index index;
160 // public typedefs for use by classes that inherit it.
163 typedef T value_type;
164 typedef T& reference;
165 typedef T const& const_reference;
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,
172 const index* strides,
173 const index*) const {
174 return *(base + idx * strides[0]);
177 value_accessor_one() { }
178 ~value_accessor_one() { }
182 /////////////////////////////////////////////////////////////////////////
183 // choose value accessor begins
186 struct choose_value_accessor_n {
187 template <typename T, std::size_t NumDims>
189 typedef value_accessor_n<T,NumDims> type;
193 struct choose_value_accessor_one {
194 template <typename T, std::size_t NumDims>
196 typedef value_accessor_one<T> type;
201 template <std::size_t NumDims>
202 struct value_accessor_gen_helper {
203 typedef choose_value_accessor_n choice;
207 struct value_accessor_gen_helper<1> {
208 typedef choose_value_accessor_one choice;
211 template <typename T, std::size_t NumDims>
212 struct value_accessor_generator {
214 typedef typename value_accessor_gen_helper<NumDims>::choice Choice;
216 typedef typename Choice::template bind<T,NumDims>::type type;
220 // choose value accessor ends
221 /////////////////////////////////////////////////////////////////////////
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;
233 struct iterator_tag_selector<1> {
234 typedef std::random_access_iterator_tag type;
238 ////////////////////////////////////////////////////////////////////////
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;
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;
254 template <std::size_t NDims>
256 typedef boost::detail::multi_array::sub_array<T,NDims> type;
259 template <std::size_t NDims>
260 struct const_subarray {
261 typedef boost::detail::multi_array::const_sub_array<T,NDims> type;
264 template <std::size_t NDims>
266 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
269 template <std::size_t NDims>
270 struct const_array_view {
272 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
279 typedef typename iterator_tag_selector<NumDims>::type iterator_tag;
282 iterator_generator<T,NumDims,value_type,
283 reference,iterator_tag,index>::type iterator;
286 const_iterator_generator<T,NumDims,value_type,
287 const_reference,iterator_tag,index>::type const_iterator;
290 reverse_iterator_generator<T,NumDims,value_type,
291 reference,iterator_tag,index>::type reverse_iterator;
294 const_reverse_iterator_generator<T,NumDims,value_type,
295 const_reference,iterator_tag,index>::type const_reverse_iterator;
298 typedef iterator_base<T,T*> iter_base;
299 typedef iterator_base<T,const T*> const_iter_base;
301 multi_array_impl_base() { }
302 ~multi_array_impl_base() { }
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 {
310 for (size_type n = 0; n != NumDims; ++n)
311 offset += indices[n] * strides[n];
316 template <typename StrideList, typename ExtentList>
317 void compute_strides(StrideList& stride_list, ExtentList& extent_list,
318 const general_storage_order<NumDims>& storage)
320 // invariant: stride = the stride for dimension n
322 for (size_type n = 0; n != NumDims; ++n) {
323 index stride_sign = +1;
325 if (!storage.ascending(storage.ordering(n)))
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;
332 stride *= extent_list[storage.ordering(n)];
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>
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)
347 calculate_descending_dimension_offset(stride_list,extent_list,
349 calculate_indexing_offset(stride_list,index_base_list);
352 // This calculates the offset added to the base pointer that are
353 // caused by descending dimensions
354 template <typename StrideList, typename ExtentList>
356 calculate_descending_dimension_offset(const StrideList& stride_list,
357 const ExtentList& extent_list,
358 const general_storage_order<NumDims>& storage)
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];
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.
373 template <typename StrideList, typename BaseList>
375 calculate_indexing_offset(const StrideList& stride_list,
376 const BaseList& index_base_list)
379 for (size_type n = 0; n != NumDims; ++n)
380 offset -= stride_list[n] * index_base_list[n];
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>
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,
403 boost::array<index,NDims> new_strides;
404 boost::array<index,NDims> new_extents;
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;
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];
421 if (!current_range.is_degenerate()) {
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];
427 // calculate new extents
428 new_extents[dim] = len;
432 assert (dim == NDims);
435 ArrayRef(base+offset,
443 } // namespace multi_array
444 } // namespace detail
448 #endif // BASE_RG071801_HPP