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

Revision 857, 14.9 KB checked in by igarcia, 19 years ago (diff)
RevLine 
[857]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
39namespace boost {
40  namespace detail {
41    namespace multi_array {
42
43      struct populate_index_ranges {
44        multi_array_types::index_range
45        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//
58template <typename T, std::size_t NumDims, typename TPtr>
59char is_multi_array_impl_help(const_multi_array_view<T,NumDims,TPtr>&);
60template <typename T, std::size_t NumDims, typename TPtr>
61char is_multi_array_impl_help(const_sub_array<T,NumDims,TPtr>&);
62template <typename T, std::size_t NumDims, typename TPtr>
63char is_multi_array_impl_help(const_multi_array_ref<T,NumDims,TPtr>&);
64
65char ( &is_multi_array_impl_help(...) )[2];
66
67template <class T>
68struct 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
76template <bool multi_array = false>
77struct disable_multi_array_impl_impl
78{
79    typedef int type;
80};
81
82template <>
83struct disable_multi_array_impl_impl<true>
84{
85    // forming a pointer to a reference triggers SFINAE
86    typedef int& type;
87};
88
89
90template <class T>
91struct disable_multi_array_impl :
92  disable_multi_array_impl_impl<is_multi_array_impl<T>::value>
93{ };
94
95
96template <>
97struct disable_multi_array_impl<int>
98{
99  typedef int type;
100};
101
102
103#endif
104
105    } //namespace multi_array
106  } // namespace detail
107
108template<typename T, std::size_t NumDims,
109  typename Allocator>
110class multi_array :
111  public multi_array_ref<T,NumDims>
112{
113  typedef multi_array_ref<T,NumDims> super_type;
114public:
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
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>
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>
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>
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
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
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
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
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>
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>
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>
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
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
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
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
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
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
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.
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
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
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
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
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   
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>
369  multi_array& operator=(const ConstMultiArray& other) {
370    super_type::operator=(other);
371    return *this;
372  }
373
374  multi_array& operator=(const multi_array& other) {
375    if (&other != this) {
376      super_type::operator=(other);
377    }
378    return *this;
379  }
380
381
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
448  ~multi_array() {
449    deallocate_space();
450  }
451
452private:
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
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
Note: See TracBrowser for help on using the repository browser.