1 // Copyright 2002 The Trustees of Indiana University.
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)
7 // Boost.MultiArray Library
8 // Authors: Ronald Garcia
11 // See http://www.boost.org/libs/multi_array for documentation.
13 #ifndef BOOST_MULTI_ARRAY_RG071801_HPP
14 #define BOOST_MULTI_ARRAY_RG071801_HPP
17 // multi_array.hpp - contains the multi_array class template
18 // declaration and definition
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"
41 namespace multi_array {
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);
51 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
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.
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>&);
65 char ( &is_multi_array_impl_help(...) )[2];
68 struct is_multi_array_impl
71 BOOST_STATIC_CONSTANT(bool, value = sizeof((is_multi_array_impl_help)(x)) == 1);
73 typedef mpl::bool_<value> type;
76 template <bool multi_array = false>
77 struct disable_multi_array_impl_impl
83 struct disable_multi_array_impl_impl<true>
85 // forming a pointer to a reference triggers SFINAE
91 struct disable_multi_array_impl :
92 disable_multi_array_impl_impl<is_multi_array_impl<T>::value>
97 struct disable_multi_array_impl<int>
105 } //namespace multi_array
106 } // namespace detail
108 template<typename T, std::size_t NumDims,
111 public multi_array_ref<T,NumDims>
113 typedef multi_array_ref<T,NumDims> super_type;
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;
129 template <std::size_t NDims>
130 struct const_array_view {
131 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
134 template <std::size_t NDims>
136 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
139 explicit multi_array() :
140 super_type((T*)initial_base_,c_storage_order(),
141 /*index_bases=*/0, /*extents=*/0) {
145 template <class ExtentList>
146 explicit multi_array(
147 ExtentList const& extents
148 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
150 detail::multi_array::is_multi_array_impl<ExtentList>,
154 super_type((T*)initial_base_,extents) {
155 boost::function_requires<
156 detail::multi_array::CollectionConcept<ExtentList> >();
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> >();
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> >();
181 explicit multi_array(const detail::multi_array
182 ::extent_gen<NumDims>& ranges) :
183 super_type((T*)initial_base_,ranges) {
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) {
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) {
207 multi_array(const multi_array& rhs) :
208 super_type(rhs), allocator_(rhs.allocator_) {
210 boost::copy_n(rhs.base_,rhs.num_elements(),base_);
215 // A multi_array is constructible from any multi_array_ref, subarray, or
216 // array_view object. The following constructors ensure that.
219 // Due to limited support for partial template ordering,
220 // MSVC 6&7 confuse the following with the most basic ExtentList
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())
229 // Warning! storage order may change, hence the following copy technique.
230 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
240 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
251 std::copy(rhs.begin(),rhs.end(),this->begin());
254 #else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
255 // More limited support for MSVC
258 multi_array(const const_multi_array_ref<T,NumDims>& rhs)
259 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape())
262 // Warning! storage order may change, hence the following copy technique.
263 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
271 // Warning! storage order may change, hence the following copy technique.
272 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
280 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
289 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
298 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
307 std::copy(rhs.begin(),rhs.end(),this->begin());
310 #endif // !BOOST_NO_FUNCTION_TEMPLATE_ORDERING
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())
317 // Warning! storage order may change, hence the following copy technique.
318 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
326 // Warning! storage order may change, hence the following copy technique.
327 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
336 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
345 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
354 std::copy(rhs.begin(),rhs.end(),this->begin());
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())
363 std::copy(rhs.begin(),rhs.end(),this->begin());
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);
374 multi_array& operator=(const multi_array& other) {
375 if (&other != this) {
376 super_type::operator=(other);
382 multi_array& resize(const detail::multi_array
383 ::extent_gen<NumDims>& ranges) {
386 // build a multi_array with the specs given
387 multi_array new_array(ranges);
390 // build a view of tmp with the minimum extents
392 // Get the minimum extents of the arrays.
393 boost::array<size_type,NumDims> min_extents;
395 const size_type& (*min)(const size_type&, const size_type&) =
397 std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(),
398 this->extent_list_.begin(),
403 // typedef boost::array<index,NumDims> index_list;
404 // Build index_gen objects to create views with the same shape
406 // these need to be separate to handle non-zero index bases
407 typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen;
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());
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());
421 // Build same-shape views of the two arrays
423 multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_old = (*this)[old_idxes];
425 multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_new = new_array[new_idxes];
427 // Set the right portion of the new array
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_);
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());
461 void deallocate_space() {
463 for(T* i = base_; i != base_+allocated_elements_; ++i)
464 allocator_.destroy(i);
465 allocator_.deallocate(base_,allocated_elements_);
469 typedef boost::array<size_type,NumDims> size_list;
470 typedef boost::array<index,NumDims> index_list;
472 Allocator allocator_;
474 size_type allocated_elements_;
475 enum {initial_base_ = 0};
480 #endif // BOOST_MULTI_ARRAY_RG071801_HPP