]> git.lyx.org Git - lyx.git/blob - boost/boost/multi_array.hpp
Boost 1.31.0
[lyx.git] / boost / boost / multi_array.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_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/type_traits.hpp"
30 #include <algorithm>
31 #include <cstddef>
32 #include <functional>
33 #include <numeric>
34 #include <vector>
35
36
37
38 namespace boost {
39   namespace detail {
40     namespace multi_array {
41       struct populate_index_ranges {
42         multi_array_types::index_range
43         operator()(multi_array_types::index base,
44                    multi_array_types::size_type extent) {
45           return multi_array_types::index_range(base,base+extent);
46         }
47       };
48     } //namespace multi_array
49   } // namespace detail
50
51 template<typename T, std::size_t NumDims,
52   typename Allocator>
53 class multi_array :
54   public multi_array_ref<T,NumDims>
55 {
56   typedef multi_array_ref<T,NumDims> super_type;
57 public:
58   typedef typename super_type::value_type value_type;
59   typedef typename super_type::reference reference;
60   typedef typename super_type::const_reference const_reference;
61   typedef typename super_type::iterator iterator;
62   typedef typename super_type::const_iterator const_iterator;
63   typedef typename super_type::reverse_iterator reverse_iterator;
64   typedef typename super_type::const_reverse_iterator const_reverse_iterator;
65   typedef typename super_type::element element;
66   typedef typename super_type::size_type size_type;
67   typedef typename super_type::difference_type difference_type;
68   typedef typename super_type::index index;
69   typedef typename super_type::extent_range extent_range;
70
71
72   template <std::size_t NDims>
73   struct const_array_view {
74     typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
75   };
76
77   template <std::size_t NDims>
78   struct array_view {
79     typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
80   };
81
82   explicit multi_array() :
83     super_type((T*)initial_base_) {
84     allocate_space();
85   }
86     
87   template <class ExtentList>
88   explicit multi_array(
89       ExtentList const& extents
90 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
91     , typename detail::multi_array::disable_non_sub_array<ExtentList>::type* = 0
92 #endif 
93   ) :
94     super_type((T*)initial_base_,extents) {
95     boost::function_requires<
96       detail::multi_array::CollectionConcept<ExtentList> >();
97     allocate_space();
98   }
99     
100   template <class ExtentList>
101   explicit multi_array(ExtentList const& extents,
102                        const general_storage_order<NumDims>& so) :
103     super_type((T*)initial_base_,extents,so) {
104     boost::function_requires<
105       detail::multi_array::CollectionConcept<ExtentList> >();
106     allocate_space();
107   }
108
109   template <class ExtentList>
110   explicit multi_array(ExtentList const& extents,
111                        const general_storage_order<NumDims>& so,
112                        Allocator const& alloc) :
113     super_type((T*)initial_base_,extents,so), allocator_(alloc) {
114     boost::function_requires<
115       detail::multi_array::CollectionConcept<ExtentList> >();
116     allocate_space();
117   }
118
119
120   explicit multi_array(const detail::multi_array
121                        ::extent_gen<NumDims>& ranges) :
122     super_type((T*)initial_base_,ranges) {
123
124     allocate_space();
125   }
126
127
128   explicit multi_array(const detail::multi_array
129                        ::extent_gen<NumDims>& ranges,
130                        const general_storage_order<NumDims>& so) :
131     super_type((T*)initial_base_,ranges,so) {
132
133     allocate_space();
134   }
135
136
137   explicit multi_array(const detail::multi_array
138                        ::extent_gen<NumDims>& ranges,
139                        const general_storage_order<NumDims>& so,
140                        Allocator const& alloc) :
141     super_type((T*)initial_base_,ranges,so), allocator_(alloc) {
142
143     allocate_space();
144   }
145
146   multi_array(const multi_array& rhs) :
147   super_type(rhs), allocator_(rhs.allocator_) {
148     allocate_space();
149     boost::copy_n(rhs.base_,rhs.num_elements(),base_);
150   }
151
152   template <typename OPtr>
153   multi_array(const detail::multi_array::
154               const_sub_array<T,NumDims,OPtr>& rhs) :
155     super_type(rhs) {
156     allocate_space();
157     std::copy(rhs.begin(),rhs.end(),this->begin());
158   }
159
160   // For some reason, gcc 2.95.2 doesn't pick the above template
161   // member function when passed a subarray, so i was forced to
162   // duplicate the functionality here...
163   multi_array(const detail::multi_array::
164               sub_array<T,NumDims>& rhs) :
165     super_type(rhs) {
166     allocate_space();
167     std::copy(rhs.begin(),rhs.end(),this->begin());
168   }
169     
170   // Since assignment is a deep copy, multi_array_ref
171   // contains all the necessary code.
172   template <typename ConstMultiArray>
173   multi_array& operator=(const ConstMultiArray& other) {
174     super_type::operator=(other);
175     return *this;
176   }
177
178   multi_array& operator=(const multi_array& other) {
179     if (&other != this) {
180       super_type::operator=(other);
181     }
182     return *this;
183   }
184
185
186   multi_array& resize(const detail::multi_array
187                       ::extent_gen<NumDims>& ranges) {
188
189
190     // build a multi_array with the specs given
191     multi_array new_array(ranges);
192
193
194     // build a view of tmp with the minimum extents
195
196     // Get the minimum extents of the arrays.
197     boost::array<size_type,NumDims> min_extents;
198
199     const size_type& (*min)(const size_type&, const size_type&) =
200       std::min;
201     std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(),
202                    this->extent_list_.begin(),
203                    min_extents.begin(),
204                    min);
205
206
207     // typedef boost::array<index,NumDims> index_list;
208     // Build index_gen objects to create views with the same shape
209
210     // these need to be separate to handle non-zero index bases
211     typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen;
212     index_gen old_idxes;
213     index_gen new_idxes;
214
215     std::transform(new_array.index_base_list_.begin(),
216                    new_array.index_base_list_.end(),
217                    min_extents.begin(),old_idxes.ranges_.begin(),
218                    detail::multi_array::populate_index_ranges());
219
220     std::transform(this->index_base_list_.begin(),
221                    this->index_base_list_.end(),
222                    min_extents.begin(),new_idxes.ranges_.begin(),
223                    detail::multi_array::populate_index_ranges());
224
225     // Build same-shape views of the two arrays
226     typename
227       multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_old = (*this)[old_idxes];
228     typename
229       multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_new = new_array[new_idxes];
230
231     // Set the right portion of the new array
232     view_new = view_old;
233
234     using std::swap;
235     // Swap the internals of these arrays.
236     swap(this->super_type::base_,new_array.super_type::base_);
237     swap(this->storage_,new_array.storage_);
238     swap(this->extent_list_,new_array.extent_list_);
239     swap(this->stride_list_,new_array.stride_list_);
240     swap(this->index_base_list_,new_array.index_base_list_);
241     swap(this->origin_offset_,new_array.origin_offset_);
242     swap(this->directional_offset_,new_array.directional_offset_);
243     swap(this->num_elements_,new_array.num_elements_);
244     swap(this->allocator_,new_array.allocator_);
245     swap(this->base_,new_array.base_);
246     swap(this->allocated_elements_,new_array.allocated_elements_);
247
248     return *this;
249   }
250
251
252   ~multi_array() {
253     deallocate_space();
254   }
255
256 private:
257   void allocate_space() {
258     typename Allocator::const_pointer no_hint=0;
259     base_ = allocator_.allocate(this->num_elements(),no_hint);
260     this->set_base_ptr(base_);
261     allocated_elements_ = this->num_elements();
262     std::uninitialized_fill_n(base_,allocated_elements_,T());
263   }
264
265   void deallocate_space() {
266     if(base_) {
267       for(T* i = base_; i != base_+allocated_elements_; ++i)
268         allocator_.destroy(i);
269       allocator_.deallocate(base_,allocated_elements_);
270     }
271   }
272
273   typedef boost::array<size_type,NumDims> size_list;
274   typedef boost::array<index,NumDims> index_list;
275
276   Allocator allocator_;
277   T* base_;
278   size_type allocated_elements_;
279   enum {initial_base_ = 0};
280 };
281
282 } // namespace boost
283
284 #endif // BOOST_MULTI_ARRAY_RG071801_HPP