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_RG071801_HPP
14 #define BOOST_MULTI_ARRAY_RG071801_HPP
15 
16 //
17 // multi_array.hpp - contains the multi_array class template
18 // declaration and definition
19 //
20 
21 #include "boost/multi_array/base.hpp"
22 #include "boost/multi_array/collection_concept.hpp"
23 #include "boost/multi_array/copy_array.hpp"
24 #include "boost/multi_array/iterator.hpp"
25 #include "boost/multi_array/subarray.hpp"
26 #include "boost/multi_array/multi_array_ref.hpp"
27 #include "boost/multi_array/algorithm.hpp"
28 #include "boost/array.hpp"
29 #include "boost/mpl/if.hpp"
30 #include "boost/type_traits.hpp"
31 #include <algorithm>
32 #include <cstddef>
33 #include <functional>
34 #include <numeric>
35 #include <vector>
36 
37 
38 
39 namespace boost {
40   namespace detail {
41     namespace multi_array {
42 
43       struct populate_index_ranges {
44         multi_array_types::index_range
operator ()boost::detail::multi_array::populate_index_ranges45         operator()(multi_array_types::index base,
46                    multi_array_types::size_type extent) {
47           return multi_array_types::index_range(base,base+extent);
48         }
49       };
50 
51 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
52 //
53 // Compilers that don't support partial ordering may need help to
54 // disambiguate multi_array's templated constructors.  Even vc6/7 are
55 // capable of some limited SFINAE, so we take the most-general version
56 // out of the overload set with disable_multi_array_impl.
57 //
58 template <typename T, std::size_t NumDims, typename TPtr>
59 char is_multi_array_impl_help(const_multi_array_view<T,NumDims,TPtr>&);
60 template <typename T, std::size_t NumDims, typename TPtr>
61 char is_multi_array_impl_help(const_sub_array<T,NumDims,TPtr>&);
62 template <typename T, std::size_t NumDims, typename TPtr>
63 char is_multi_array_impl_help(const_multi_array_ref<T,NumDims,TPtr>&);
64 
65 char ( &is_multi_array_impl_help(...) )[2];
66 
67 template <class T>
68 struct is_multi_array_impl
69 {
70     static T x;
71     BOOST_STATIC_CONSTANT(bool, value = sizeof((is_multi_array_impl_help)(x)) == 1);
72 
73   typedef mpl::bool_<value> type;
74 };
75 
76 template <bool multi_array = false>
77 struct disable_multi_array_impl_impl
78 {
79     typedef int type;
80 };
81 
82 template <>
83 struct disable_multi_array_impl_impl<true>
84 {
85     // forming a pointer to a reference triggers SFINAE
86     typedef int& type;
87 };
88 
89 
90 template <class T>
91 struct disable_multi_array_impl :
92   disable_multi_array_impl_impl<is_multi_array_impl<T>::value>
93 { };
94 
95 
96 template <>
97 struct disable_multi_array_impl<int>
98 {
99   typedef int type;
100 };
101 
102 
103 #endif
104 
105     } //namespace multi_array
106   } // namespace detail
107 
108 template<typename T, std::size_t NumDims,
109   typename Allocator>
110 class multi_array :
111   public multi_array_ref<T,NumDims>
112 {
113   typedef multi_array_ref<T,NumDims> super_type;
114 public:
115   typedef typename super_type::value_type value_type;
116   typedef typename super_type::reference reference;
117   typedef typename super_type::const_reference const_reference;
118   typedef typename super_type::iterator iterator;
119   typedef typename super_type::const_iterator const_iterator;
120   typedef typename super_type::reverse_iterator reverse_iterator;
121   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
122   typedef typename super_type::element element;
123   typedef typename super_type::size_type size_type;
124   typedef typename super_type::difference_type difference_type;
125   typedef typename super_type::index index;
126   typedef typename super_type::extent_range extent_range;
127 
128 
129   template <std::size_t NDims>
130   struct const_array_view {
131     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
132   };
133 
134   template <std::size_t NDims>
135   struct array_view {
136     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
137   };
138 
multi_array()139   explicit multi_array() :
140     super_type((T*)initial_base_,c_storage_order(),
141                /*index_bases=*/0, /*extents=*/0) {
142     allocate_space();
143   }
144 
145   template <class ExtentList>
multi_array(ExtentList const & extents,typename mpl::if_<detail::multi_array::is_multi_array_impl<ExtentList>,int &,int>::type * =0)146   explicit multi_array(
147       ExtentList const& extents
148 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
149       , typename mpl::if_<
150       detail::multi_array::is_multi_array_impl<ExtentList>,
151       int&,int>::type* = 0
152 #endif
153       ) :
154     super_type((T*)initial_base_,extents) {
155     boost::function_requires<
156       detail::multi_array::CollectionConcept<ExtentList> >();
157     allocate_space();
158   }
159 
160 
161   template <class ExtentList>
multi_array(ExtentList const & extents,const general_storage_order<NumDims> & so)162   explicit multi_array(ExtentList const& extents,
163                        const general_storage_order<NumDims>& so) :
164     super_type((T*)initial_base_,extents,so) {
165     boost::function_requires<
166       detail::multi_array::CollectionConcept<ExtentList> >();
167     allocate_space();
168   }
169 
170   template <class ExtentList>
multi_array(ExtentList const & extents,const general_storage_order<NumDims> & so,Allocator const & alloc)171   explicit multi_array(ExtentList const& extents,
172                        const general_storage_order<NumDims>& so,
173                        Allocator const& alloc) :
174     super_type((T*)initial_base_,extents,so), allocator_(alloc) {
175     boost::function_requires<
176       detail::multi_array::CollectionConcept<ExtentList> >();
177     allocate_space();
178   }
179 
180 
multi_array(const detail::multi_array::extent_gen<NumDims> & ranges)181   explicit multi_array(const detail::multi_array
182                        ::extent_gen<NumDims>& ranges) :
183     super_type((T*)initial_base_,ranges) {
184 
185     allocate_space();
186   }
187 
188 
multi_array(const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so)189   explicit multi_array(const detail::multi_array
190                        ::extent_gen<NumDims>& ranges,
191                        const general_storage_order<NumDims>& so) :
192     super_type((T*)initial_base_,ranges,so) {
193 
194     allocate_space();
195   }
196 
197 
multi_array(const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so,Allocator const & alloc)198   explicit multi_array(const detail::multi_array
199                        ::extent_gen<NumDims>& ranges,
200                        const general_storage_order<NumDims>& so,
201                        Allocator const& alloc) :
202     super_type((T*)initial_base_,ranges,so), allocator_(alloc) {
203 
204     allocate_space();
205   }
206 
multi_array(const multi_array & rhs)207   multi_array(const multi_array& rhs) :
208   super_type(rhs), allocator_(rhs.allocator_) {
209     allocate_space();
210     boost::detail::multi_array::copy_n(rhs.base_,rhs.num_elements(),base_);
211   }
212 
213 
214   //
215   // A multi_array is constructible from any multi_array_ref, subarray, or
216   // array_view object.  The following constructors ensure that.
217   //
218 
219   // Due to limited support for partial template ordering,
220   // MSVC 6&7 confuse the following with the most basic ExtentList
221   // constructor.
222 #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
223   template <typename OPtr>
multi_array(const const_multi_array_ref<T,NumDims,OPtr> & rhs,const general_storage_order<NumDims> & so=c_storage_order ())224   multi_array(const const_multi_array_ref<T,NumDims,OPtr>& rhs,
225               const general_storage_order<NumDims>& so = c_storage_order())
226     : super_type(0,so,rhs.index_bases(),rhs.shape())
227   {
228     allocate_space();
229     // Warning! storage order may change, hence the following copy technique.
230     std::copy(rhs.begin(),rhs.end(),this->begin());
231   }
232 
233   template <typename OPtr>
multi_array(const detail::multi_array::const_sub_array<T,NumDims,OPtr> & rhs,const general_storage_order<NumDims> & so=c_storage_order ())234   multi_array(const detail::multi_array::
235               const_sub_array<T,NumDims,OPtr>& rhs,
236               const general_storage_order<NumDims>& so = c_storage_order())
237     : super_type(0,so,rhs.index_bases(),rhs.shape())
238   {
239     allocate_space();
240     std::copy(rhs.begin(),rhs.end(),this->begin());
241   }
242 
243 
244   template <typename OPtr>
multi_array(const detail::multi_array::const_multi_array_view<T,NumDims,OPtr> & rhs,const general_storage_order<NumDims> & so=c_storage_order ())245   multi_array(const detail::multi_array::
246               const_multi_array_view<T,NumDims,OPtr>& rhs,
247               const general_storage_order<NumDims>& so = c_storage_order())
248     : super_type(0,so,rhs.index_bases(),rhs.shape())
249   {
250     allocate_space();
251     std::copy(rhs.begin(),rhs.end(),this->begin());
252   }
253 
254 #else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
255   // More limited support for MSVC
256 
257 
multi_array(const const_multi_array_ref<T,NumDims> & rhs)258   multi_array(const const_multi_array_ref<T,NumDims>& rhs)
259     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
260   {
261     allocate_space();
262     // Warning! storage order may change, hence the following copy technique.
263     std::copy(rhs.begin(),rhs.end(),this->begin());
264   }
265 
multi_array(const const_multi_array_ref<T,NumDims> & rhs,const general_storage_order<NumDims> & so)266   multi_array(const const_multi_array_ref<T,NumDims>& rhs,
267               const general_storage_order<NumDims>& so)
268     : super_type(0,so,rhs.index_bases(),rhs.shape())
269   {
270     allocate_space();
271     // Warning! storage order may change, hence the following copy technique.
272     std::copy(rhs.begin(),rhs.end(),this->begin());
273   }
274 
multi_array(const detail::multi_array::const_sub_array<T,NumDims> & rhs)275   multi_array(const detail::multi_array::
276               const_sub_array<T,NumDims>& rhs)
277     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
278   {
279     allocate_space();
280     std::copy(rhs.begin(),rhs.end(),this->begin());
281   }
282 
multi_array(const detail::multi_array::const_sub_array<T,NumDims> & rhs,const general_storage_order<NumDims> & so)283   multi_array(const detail::multi_array::
284               const_sub_array<T,NumDims>& rhs,
285               const general_storage_order<NumDims>& so)
286     : super_type(0,so,rhs.index_bases(),rhs.shape())
287   {
288     allocate_space();
289     std::copy(rhs.begin(),rhs.end(),this->begin());
290   }
291 
292 
multi_array(const detail::multi_array::const_multi_array_view<T,NumDims> & rhs)293   multi_array(const detail::multi_array::
294               const_multi_array_view<T,NumDims>& rhs)
295     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
296   {
297     allocate_space();
298     std::copy(rhs.begin(),rhs.end(),this->begin());
299   }
300 
multi_array(const detail::multi_array::const_multi_array_view<T,NumDims> & rhs,const general_storage_order<NumDims> & so)301   multi_array(const detail::multi_array::
302               const_multi_array_view<T,NumDims>& rhs,
303               const general_storage_order<NumDims>& so)
304     : super_type(0,so,rhs.index_bases(),rhs.shape())
305   {
306     allocate_space();
307     std::copy(rhs.begin(),rhs.end(),this->begin());
308   }
309 
310 #endif // !BOOST_NO_FUNCTION_TEMPLATE_ORDERING
311 
312   // Thes constructors are necessary because of more exact template matches.
multi_array(const multi_array_ref<T,NumDims> & rhs)313   multi_array(const multi_array_ref<T,NumDims>& rhs)
314     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
315   {
316     allocate_space();
317     // Warning! storage order may change, hence the following copy technique.
318     std::copy(rhs.begin(),rhs.end(),this->begin());
319   }
320 
multi_array(const multi_array_ref<T,NumDims> & rhs,const general_storage_order<NumDims> & so)321   multi_array(const multi_array_ref<T,NumDims>& rhs,
322               const general_storage_order<NumDims>& so)
323     : super_type(0,so,rhs.index_bases(),rhs.shape())
324   {
325     allocate_space();
326     // Warning! storage order may change, hence the following copy technique.
327     std::copy(rhs.begin(),rhs.end(),this->begin());
328   }
329 
330 
multi_array(const detail::multi_array::sub_array<T,NumDims> & rhs)331   multi_array(const detail::multi_array::
332               sub_array<T,NumDims>& rhs)
333     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
334   {
335     allocate_space();
336     std::copy(rhs.begin(),rhs.end(),this->begin());
337   }
338 
multi_array(const detail::multi_array::sub_array<T,NumDims> & rhs,const general_storage_order<NumDims> & so)339   multi_array(const detail::multi_array::
340               sub_array<T,NumDims>& rhs,
341               const general_storage_order<NumDims>& so)
342     : super_type(0,so,rhs.index_bases(),rhs.shape())
343   {
344     allocate_space();
345     std::copy(rhs.begin(),rhs.end(),this->begin());
346   }
347 
348 
multi_array(const detail::multi_array::multi_array_view<T,NumDims> & rhs)349   multi_array(const detail::multi_array::
350               multi_array_view<T,NumDims>& rhs)
351     : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
352   {
353     allocate_space();
354     std::copy(rhs.begin(),rhs.end(),this->begin());
355   }
356 
multi_array(const detail::multi_array::multi_array_view<T,NumDims> & rhs,const general_storage_order<NumDims> & so)357   multi_array(const detail::multi_array::
358               multi_array_view<T,NumDims>& rhs,
359               const general_storage_order<NumDims>& so)
360     : super_type(0,so,rhs.index_bases(),rhs.shape())
361   {
362     allocate_space();
363     std::copy(rhs.begin(),rhs.end(),this->begin());
364   }
365 
366   // Since assignment is a deep copy, multi_array_ref
367   // contains all the necessary code.
368   template <typename ConstMultiArray>
operator =(const ConstMultiArray & other)369   multi_array& operator=(const ConstMultiArray& other) {
370     super_type::operator=(other);
371     return *this;
372   }
373 
operator =(const multi_array & other)374   multi_array& operator=(const multi_array& other) {
375     if (&other != this) {
376       super_type::operator=(other);
377     }
378     return *this;
379   }
380 
381 
resize(const detail::multi_array::extent_gen<NumDims> & ranges)382   multi_array& resize(const detail::multi_array
383                       ::extent_gen<NumDims>& ranges) {
384 
385 
386     // build a multi_array with the specs given
387     multi_array new_array(ranges);
388 
389 
390     // build a view of tmp with the minimum extents
391 
392     // Get the minimum extents of the arrays.
393     boost::array<size_type,NumDims> min_extents;
394 
395     const size_type& (*min)(const size_type&, const size_type&) =
396       std::min;
397     std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(),
398                    this->extent_list_.begin(),
399                    min_extents.begin(),
400                    min);
401 
402 
403     // typedef boost::array<index,NumDims> index_list;
404     // Build index_gen objects to create views with the same shape
405 
406     // these need to be separate to handle non-zero index bases
407     typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen;
408     index_gen old_idxes;
409     index_gen new_idxes;
410 
411     std::transform(new_array.index_base_list_.begin(),
412                    new_array.index_base_list_.end(),
413                    min_extents.begin(),old_idxes.ranges_.begin(),
414                    detail::multi_array::populate_index_ranges());
415 
416     std::transform(this->index_base_list_.begin(),
417                    this->index_base_list_.end(),
418                    min_extents.begin(),new_idxes.ranges_.begin(),
419                    detail::multi_array::populate_index_ranges());
420 
421     // Build same-shape views of the two arrays
422     typename
423       multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_old = (*this)[old_idxes];
424     typename
425       multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_new = new_array[new_idxes];
426 
427     // Set the right portion of the new array
428     view_new = view_old;
429 
430     using std::swap;
431     // Swap the internals of these arrays.
432     swap(this->super_type::base_,new_array.super_type::base_);
433     swap(this->storage_,new_array.storage_);
434     swap(this->extent_list_,new_array.extent_list_);
435     swap(this->stride_list_,new_array.stride_list_);
436     swap(this->index_base_list_,new_array.index_base_list_);
437     swap(this->origin_offset_,new_array.origin_offset_);
438     swap(this->directional_offset_,new_array.directional_offset_);
439     swap(this->num_elements_,new_array.num_elements_);
440     swap(this->allocator_,new_array.allocator_);
441     swap(this->base_,new_array.base_);
442     swap(this->allocated_elements_,new_array.allocated_elements_);
443 
444     return *this;
445   }
446 
447 
~multi_array()448   ~multi_array() {
449     deallocate_space();
450   }
451 
452 private:
allocate_space()453   void allocate_space() {
454     typename Allocator::const_pointer no_hint=0;
455     base_ = allocator_.allocate(this->num_elements(),no_hint);
456     this->set_base_ptr(base_);
457     allocated_elements_ = this->num_elements();
458     std::uninitialized_fill_n(base_,allocated_elements_,T());
459   }
460 
deallocate_space()461   void deallocate_space() {
462     if(base_) {
463       for(T* i = base_; i != base_+allocated_elements_; ++i)
464         allocator_.destroy(i);
465       allocator_.deallocate(base_,allocated_elements_);
466     }
467   }
468 
469   typedef boost::array<size_type,NumDims> size_list;
470   typedef boost::array<index,NumDims> index_list;
471 
472   Allocator allocator_;
473   T* base_;
474   size_type allocated_elements_;
475   enum {initial_base_ = 0};
476 };
477 
478 } // namespace boost
479 
480 #endif // BOOST_MULTI_ARRAY_RG071801_HPP
481