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 // RG: underscore on extent_ to stifle strange MSVC warning.
46 operator()(multi_array_types::index base
,
47 multi_array_types::size_type extent_
) {
48 return multi_array_types::index_range(base
,base
+extent_
);
52 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
54 // Compilers that don't support partial ordering may need help to
55 // disambiguate multi_array's templated constructors. Even vc6/7 are
56 // capable of some limited SFINAE, so we take the most-general version
57 // out of the overload set with disable_multi_array_impl.
59 template <typename T
, std::size_t NumDims
, typename TPtr
>
60 char is_multi_array_impl_help(const_multi_array_view
<T
,NumDims
,TPtr
>&);
61 template <typename T
, std::size_t NumDims
, typename TPtr
>
62 char is_multi_array_impl_help(const_sub_array
<T
,NumDims
,TPtr
>&);
63 template <typename T
, std::size_t NumDims
, typename TPtr
>
64 char is_multi_array_impl_help(const_multi_array_ref
<T
,NumDims
,TPtr
>&);
66 char ( &is_multi_array_impl_help(...) )[2];
69 struct is_multi_array_impl
72 BOOST_STATIC_CONSTANT(bool, value
= sizeof((is_multi_array_impl_help
)(x
)) == 1);
74 typedef mpl::bool_
<value
> type
;
77 template <bool multi_array
= false>
78 struct disable_multi_array_impl_impl
84 struct disable_multi_array_impl_impl
<true>
86 // forming a pointer to a reference triggers SFINAE
92 struct disable_multi_array_impl
:
93 disable_multi_array_impl_impl
<is_multi_array_impl
<T
>::value
>
98 struct disable_multi_array_impl
<int>
106 } //namespace multi_array
107 } // namespace detail
109 template<typename T
, std::size_t NumDims
,
112 public multi_array_ref
<T
,NumDims
>
114 typedef multi_array_ref
<T
,NumDims
> super_type
;
116 typedef typename
super_type::value_type value_type
;
117 typedef typename
super_type::reference reference
;
118 typedef typename
super_type::const_reference const_reference
;
119 typedef typename
super_type::iterator iterator
;
120 typedef typename
super_type::const_iterator const_iterator
;
121 typedef typename
super_type::reverse_iterator reverse_iterator
;
122 typedef typename
super_type::const_reverse_iterator const_reverse_iterator
;
123 typedef typename
super_type::element element
;
124 typedef typename
super_type::size_type size_type
;
125 typedef typename
super_type::difference_type difference_type
;
126 typedef typename
super_type::index index
;
127 typedef typename
super_type::extent_range extent_range
;
130 template <std::size_t NDims
>
131 struct const_array_view
{
132 typedef boost::detail::multi_array::const_multi_array_view
<T
,NDims
> type
;
135 template <std::size_t NDims
>
137 typedef boost::detail::multi_array::multi_array_view
<T
,NDims
> type
;
140 explicit multi_array() :
141 super_type((T
*)initial_base_
,c_storage_order(),
142 /*index_bases=*/0, /*extents=*/0) {
146 template <class ExtentList
>
147 explicit multi_array(
148 ExtentList
const& extents
149 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
151 detail::multi_array::is_multi_array_impl
<ExtentList
>,
155 super_type((T
*)initial_base_
,extents
) {
156 boost::function_requires
<
157 detail::multi_array::CollectionConcept
<ExtentList
> >();
162 template <class ExtentList
>
163 explicit multi_array(ExtentList
const& extents
,
164 const general_storage_order
<NumDims
>& so
) :
165 super_type((T
*)initial_base_
,extents
,so
) {
166 boost::function_requires
<
167 detail::multi_array::CollectionConcept
<ExtentList
> >();
171 template <class ExtentList
>
172 explicit multi_array(ExtentList
const& extents
,
173 const general_storage_order
<NumDims
>& so
,
174 Allocator
const& alloc
) :
175 super_type((T
*)initial_base_
,extents
,so
), allocator_(alloc
) {
176 boost::function_requires
<
177 detail::multi_array::CollectionConcept
<ExtentList
> >();
182 explicit multi_array(const detail::multi_array
183 ::extent_gen
<NumDims
>& ranges
) :
184 super_type((T
*)initial_base_
,ranges
) {
190 explicit multi_array(const detail::multi_array
191 ::extent_gen
<NumDims
>& ranges
,
192 const general_storage_order
<NumDims
>& so
) :
193 super_type((T
*)initial_base_
,ranges
,so
) {
199 explicit multi_array(const detail::multi_array
200 ::extent_gen
<NumDims
>& ranges
,
201 const general_storage_order
<NumDims
>& so
,
202 Allocator
const& alloc
) :
203 super_type((T
*)initial_base_
,ranges
,so
), allocator_(alloc
) {
208 multi_array(const multi_array
& rhs
) :
209 super_type(rhs
), allocator_(rhs
.allocator_
) {
211 boost::detail::multi_array::copy_n(rhs
.base_
,rhs
.num_elements(),base_
);
216 // A multi_array is constructible from any multi_array_ref, subarray, or
217 // array_view object. The following constructors ensure that.
220 // Due to limited support for partial template ordering,
221 // MSVC 6&7 confuse the following with the most basic ExtentList
223 #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
224 template <typename OPtr
>
225 multi_array(const const_multi_array_ref
<T
,NumDims
,OPtr
>& rhs
,
226 const general_storage_order
<NumDims
>& so
= c_storage_order())
227 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
230 // Warning! storage order may change, hence the following copy technique.
231 std::copy(rhs
.begin(),rhs
.end(),this->begin());
234 template <typename OPtr
>
235 multi_array(const detail::multi_array::
236 const_sub_array
<T
,NumDims
,OPtr
>& rhs
,
237 const general_storage_order
<NumDims
>& so
= c_storage_order())
238 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
241 std::copy(rhs
.begin(),rhs
.end(),this->begin());
245 template <typename OPtr
>
246 multi_array(const detail::multi_array::
247 const_multi_array_view
<T
,NumDims
,OPtr
>& rhs
,
248 const general_storage_order
<NumDims
>& so
= c_storage_order())
249 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
252 std::copy(rhs
.begin(),rhs
.end(),this->begin());
255 #else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
256 // More limited support for MSVC
259 multi_array(const const_multi_array_ref
<T
,NumDims
>& rhs
)
260 : super_type(0,c_storage_order(),rhs
.index_bases(),rhs
.shape())
263 // Warning! storage order may change, hence the following copy technique.
264 std::copy(rhs
.begin(),rhs
.end(),this->begin());
267 multi_array(const const_multi_array_ref
<T
,NumDims
>& rhs
,
268 const general_storage_order
<NumDims
>& so
)
269 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
272 // Warning! storage order may change, hence the following copy technique.
273 std::copy(rhs
.begin(),rhs
.end(),this->begin());
276 multi_array(const detail::multi_array::
277 const_sub_array
<T
,NumDims
>& rhs
)
278 : super_type(0,c_storage_order(),rhs
.index_bases(),rhs
.shape())
281 std::copy(rhs
.begin(),rhs
.end(),this->begin());
284 multi_array(const detail::multi_array::
285 const_sub_array
<T
,NumDims
>& rhs
,
286 const general_storage_order
<NumDims
>& so
)
287 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
290 std::copy(rhs
.begin(),rhs
.end(),this->begin());
294 multi_array(const detail::multi_array::
295 const_multi_array_view
<T
,NumDims
>& rhs
)
296 : super_type(0,c_storage_order(),rhs
.index_bases(),rhs
.shape())
299 std::copy(rhs
.begin(),rhs
.end(),this->begin());
302 multi_array(const detail::multi_array::
303 const_multi_array_view
<T
,NumDims
>& rhs
,
304 const general_storage_order
<NumDims
>& so
)
305 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
308 std::copy(rhs
.begin(),rhs
.end(),this->begin());
311 #endif // !BOOST_NO_FUNCTION_TEMPLATE_ORDERING
313 // Thes constructors are necessary because of more exact template matches.
314 multi_array(const multi_array_ref
<T
,NumDims
>& rhs
)
315 : super_type(0,c_storage_order(),rhs
.index_bases(),rhs
.shape())
318 // Warning! storage order may change, hence the following copy technique.
319 std::copy(rhs
.begin(),rhs
.end(),this->begin());
322 multi_array(const multi_array_ref
<T
,NumDims
>& rhs
,
323 const general_storage_order
<NumDims
>& so
)
324 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
327 // Warning! storage order may change, hence the following copy technique.
328 std::copy(rhs
.begin(),rhs
.end(),this->begin());
332 multi_array(const detail::multi_array::
333 sub_array
<T
,NumDims
>& rhs
)
334 : super_type(0,c_storage_order(),rhs
.index_bases(),rhs
.shape())
337 std::copy(rhs
.begin(),rhs
.end(),this->begin());
340 multi_array(const detail::multi_array::
341 sub_array
<T
,NumDims
>& rhs
,
342 const general_storage_order
<NumDims
>& so
)
343 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
346 std::copy(rhs
.begin(),rhs
.end(),this->begin());
350 multi_array(const detail::multi_array::
351 multi_array_view
<T
,NumDims
>& rhs
)
352 : super_type(0,c_storage_order(),rhs
.index_bases(),rhs
.shape())
355 std::copy(rhs
.begin(),rhs
.end(),this->begin());
358 multi_array(const detail::multi_array::
359 multi_array_view
<T
,NumDims
>& rhs
,
360 const general_storage_order
<NumDims
>& so
)
361 : super_type(0,so
,rhs
.index_bases(),rhs
.shape())
364 std::copy(rhs
.begin(),rhs
.end(),this->begin());
367 // Since assignment is a deep copy, multi_array_ref
368 // contains all the necessary code.
369 template <typename ConstMultiArray
>
370 multi_array
& operator=(const ConstMultiArray
& other
) {
371 super_type::operator=(other
);
375 multi_array
& operator=(const multi_array
& other
) {
376 if (&other
!= this) {
377 super_type::operator=(other
);
383 template <typename ExtentList
>
384 multi_array
& resize(const ExtentList
& extents
) {
385 boost::function_requires
<
386 detail::multi_array::CollectionConcept
<ExtentList
> >();
388 typedef detail::multi_array::extent_gen
<NumDims
> gen_type
;
391 for (int i
=0; i
!= NumDims
; ++i
) {
392 typedef typename
gen_type::range range_type
;
393 ranges
.ranges_
[i
] = range_type(0,extents
[i
]);
396 return this->resize(ranges
);
401 multi_array
& resize(const detail::multi_array
402 ::extent_gen
<NumDims
>& ranges
) {
405 // build a multi_array with the specs given
406 multi_array
new_array(ranges
,this->storage_order());
409 // build a view of tmp with the minimum extents
411 // Get the minimum extents of the arrays.
412 boost::array
<size_type
,NumDims
> min_extents
;
414 const size_type
& (*min
)(const size_type
&, const size_type
&) =
416 std::transform(new_array
.extent_list_
.begin(),new_array
.extent_list_
.end(),
417 this->extent_list_
.begin(),
422 // typedef boost::array<index,NumDims> index_list;
423 // Build index_gen objects to create views with the same shape
425 // these need to be separate to handle non-zero index bases
426 typedef detail::multi_array::index_gen
<NumDims
,NumDims
> index_gen
;
430 std::transform(new_array
.index_base_list_
.begin(),
431 new_array
.index_base_list_
.end(),
432 min_extents
.begin(),new_idxes
.ranges_
.begin(),
433 detail::multi_array::populate_index_ranges());
435 std::transform(this->index_base_list_
.begin(),
436 this->index_base_list_
.end(),
437 min_extents
.begin(),old_idxes
.ranges_
.begin(),
438 detail::multi_array::populate_index_ranges());
440 // Build same-shape views of the two arrays
442 multi_array::BOOST_NESTED_TEMPLATE array_view
<NumDims
>::type view_old
= (*this)[old_idxes
];
444 multi_array::BOOST_NESTED_TEMPLATE array_view
<NumDims
>::type view_new
= new_array
[new_idxes
];
446 // Set the right portion of the new array
450 // Swap the internals of these arrays.
451 swap(this->super_type::base_
,new_array
.super_type::base_
);
452 swap(this->storage_
,new_array
.storage_
);
453 swap(this->extent_list_
,new_array
.extent_list_
);
454 swap(this->stride_list_
,new_array
.stride_list_
);
455 swap(this->index_base_list_
,new_array
.index_base_list_
);
456 swap(this->origin_offset_
,new_array
.origin_offset_
);
457 swap(this->directional_offset_
,new_array
.directional_offset_
);
458 swap(this->num_elements_
,new_array
.num_elements_
);
459 swap(this->allocator_
,new_array
.allocator_
);
460 swap(this->base_
,new_array
.base_
);
461 swap(this->allocated_elements_
,new_array
.allocated_elements_
);
472 void allocate_space() {
473 typename
Allocator::const_pointer no_hint
=0;
474 base_
= allocator_
.allocate(this->num_elements(),no_hint
);
475 this->set_base_ptr(base_
);
476 allocated_elements_
= this->num_elements();
477 std::uninitialized_fill_n(base_
,allocated_elements_
,T());
480 void deallocate_space() {
482 for(T
* i
= base_
; i
!= base_
+allocated_elements_
; ++i
)
483 allocator_
.destroy(i
);
484 allocator_
.deallocate(base_
,allocated_elements_
);
488 typedef boost::array
<size_type
,NumDims
> size_list
;
489 typedef boost::array
<index
,NumDims
> index_list
;
491 Allocator allocator_
;
493 size_type allocated_elements_
;
494 enum {initial_base_
= 0};
499 #endif // BOOST_MULTI_ARRAY_RG071801_HPP