1// Copyright 2002 The Trustees of Indiana University.
2
3// Copyright 2018 Glen Joseph Fernandes
4// (glenjofe@gmail.com)
5
6// Use, modification and distribution is subject to the Boost Software
7// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9
10// Boost.MultiArray Library
11// Authors: Ronald Garcia
12// Jeremy Siek
13// Andrew Lumsdaine
14// See http://www.boost.org/libs/multi_array for documentation.
15
16#ifndef BOOST_MULTI_ARRAY_HPP
17#define BOOST_MULTI_ARRAY_HPP
18
19//
20// multi_array.hpp - contains the multi_array class template
21// declaration and definition
22//
23
24#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
25# pragma GCC diagnostic push
26# pragma GCC diagnostic ignored "-Wshadow"
27#endif
28
29#include "boost/multi_array/base.hpp"
30#include "boost/multi_array/collection_concept.hpp"
31#include "boost/multi_array/copy_array.hpp"
32#include "boost/multi_array/iterator.hpp"
33#include "boost/multi_array/subarray.hpp"
34#include "boost/multi_array/multi_array_ref.hpp"
35#include "boost/multi_array/algorithm.hpp"
36#include "boost/core/alloc_construct.hpp"
37#include "boost/core/empty_value.hpp"
38#include "boost/array.hpp"
39#include "boost/mpl/if.hpp"
40#include "boost/type_traits.hpp"
41#include <algorithm>
42#include <cstddef>
43#include <functional>
44#include <numeric>
45#include <vector>
46
47
48
49namespace boost {
50 namespace detail {
51 namespace multi_array {
52
53 struct populate_index_ranges {
54 multi_array_types::index_range
55 // RG: underscore on extent_ to stifle strange MSVC warning.
56 operator()(multi_array_types::index base,
57 multi_array_types::size_type extent_) {
58 return multi_array_types::index_range(base,base+extent_);
59 }
60 };
61
62#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
63//
64// Compilers that don't support partial ordering may need help to
65// disambiguate multi_array's templated constructors. Even vc6/7 are
66// capable of some limited SFINAE, so we take the most-general version
67// out of the overload set with disable_multi_array_impl.
68//
69template <typename T, std::size_t NumDims, typename TPtr>
70char is_multi_array_impl_help(const_multi_array_view<T,NumDims,TPtr>&);
71template <typename T, std::size_t NumDims, typename TPtr>
72char is_multi_array_impl_help(const_sub_array<T,NumDims,TPtr>&);
73template <typename T, std::size_t NumDims, typename TPtr>
74char is_multi_array_impl_help(const_multi_array_ref<T,NumDims,TPtr>&);
75
76char ( &is_multi_array_impl_help(...) )[2];
77
78template <class T>
79struct is_multi_array_impl
80{
81 static T x;
82 BOOST_STATIC_CONSTANT(bool, value = sizeof((is_multi_array_impl_help)(x)) == 1);
83
84 typedef mpl::bool_<value> type;
85};
86
87template <bool multi_array = false>
88struct disable_multi_array_impl_impl
89{
90 typedef int type;
91};
92
93template <>
94struct disable_multi_array_impl_impl<true>
95{
96 // forming a pointer to a reference triggers SFINAE
97 typedef int& type;
98};
99
100
101template <class T>
102struct disable_multi_array_impl :
103 disable_multi_array_impl_impl<is_multi_array_impl<T>::value>
104{ };
105
106
107template <>
108struct disable_multi_array_impl<int>
109{
110 typedef int type;
111};
112
113
114#endif
115
116 } //namespace multi_array
117 } // namespace detail
118
119template<typename T, std::size_t NumDims,
120 typename Allocator>
121class multi_array :
122 public multi_array_ref<T,NumDims>,
123 private boost::empty_value<Allocator>
124{
125 typedef boost::empty_value<Allocator> alloc_base;
126 typedef multi_array_ref<T,NumDims> super_type;
127public:
128 typedef typename super_type::value_type value_type;
129 typedef typename super_type::reference reference;
130 typedef typename super_type::const_reference const_reference;
131 typedef typename super_type::iterator iterator;
132 typedef typename super_type::const_iterator const_iterator;
133 typedef typename super_type::reverse_iterator reverse_iterator;
134 typedef typename super_type::const_reverse_iterator const_reverse_iterator;
135 typedef typename super_type::element element;
136 typedef typename super_type::size_type size_type;
137 typedef typename super_type::difference_type difference_type;
138 typedef typename super_type::index index;
139 typedef typename super_type::extent_range extent_range;
140
141
142 template <std::size_t NDims>
143 struct const_array_view {
144 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type;
145 };
146
147 template <std::size_t NDims>
148 struct array_view {
149 typedef boost::detail::multi_array::multi_array_view<T,NDims> type;
150 };
151
152 explicit multi_array(const Allocator& alloc = Allocator()) :
153 super_type((T*)initial_base_,c_storage_order(),
154 /*index_bases=*/0, /*extents=*/0),
155 alloc_base(boost::empty_init_t(),alloc) {
156 allocate_space();
157 }
158
159 template <class ExtentList>
160 explicit multi_array(
161 ExtentList const& extents,
162 const Allocator& alloc = Allocator()
163#ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
164 , typename mpl::if_<
165 detail::multi_array::is_multi_array_impl<ExtentList>,
166 int&,int>::type* = 0
167#endif
168 ) :
169 super_type((T*)initial_base_,extents),
170 alloc_base(boost::empty_init_t(),alloc) {
171 boost::function_requires<
172 detail::multi_array::CollectionConcept<ExtentList> >();
173 allocate_space();
174 }
175
176
177 template <class ExtentList>
178 explicit multi_array(ExtentList const& extents,
179 const general_storage_order<NumDims>& so) :
180 super_type((T*)initial_base_,extents,so),
181 alloc_base(boost::empty_init_t()) {
182 boost::function_requires<
183 detail::multi_array::CollectionConcept<ExtentList> >();
184 allocate_space();
185 }
186
187 template <class ExtentList>
188 explicit multi_array(ExtentList const& extents,
189 const general_storage_order<NumDims>& so,
190 Allocator const& alloc) :
191 super_type((T*)initial_base_,extents,so),
192 alloc_base(boost::empty_init_t(),alloc) {
193 boost::function_requires<
194 detail::multi_array::CollectionConcept<ExtentList> >();
195 allocate_space();
196 }
197
198
199 explicit multi_array(const detail::multi_array
200 ::extent_gen<NumDims>& ranges,
201 const Allocator& alloc = Allocator()) :
202 super_type((T*)initial_base_,ranges),
203 alloc_base(boost::empty_init_t(),alloc) {
204
205 allocate_space();
206 }
207
208
209 explicit multi_array(const detail::multi_array
210 ::extent_gen<NumDims>& ranges,
211 const general_storage_order<NumDims>& so) :
212 super_type((T*)initial_base_,ranges,so),
213 alloc_base(boost::empty_init_t()) {
214
215 allocate_space();
216 }
217
218
219 explicit multi_array(const detail::multi_array
220 ::extent_gen<NumDims>& ranges,
221 const general_storage_order<NumDims>& so,
222 Allocator const& alloc) :
223 super_type((T*)initial_base_,ranges,so),
224 alloc_base(boost::empty_init_t(),alloc) {
225
226 allocate_space();
227 }
228
229 multi_array(const multi_array& rhs) :
230 super_type(rhs),
231 alloc_base(static_cast<const alloc_base&>(rhs)) {
232 allocate_space();
233 boost::detail::multi_array::copy_n(rhs.base_,rhs.num_elements(),base_);
234 }
235
236
237 //
238 // A multi_array is constructible from any multi_array_ref, subarray, or
239 // array_view object. The following constructors ensure that.
240 //
241
242 // Due to limited support for partial template ordering,
243 // MSVC 6&7 confuse the following with the most basic ExtentList
244 // constructor.
245#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
246 template <typename OPtr>
247 multi_array(const const_multi_array_ref<T,NumDims,OPtr>& rhs,
248 const general_storage_order<NumDims>& so = c_storage_order(),
249 const Allocator& alloc = Allocator())
250 : super_type(0,so,rhs.index_bases(),rhs.shape()),
251 alloc_base(boost::empty_init_t(),alloc)
252 {
253 allocate_space();
254 // Warning! storage order may change, hence the following copy technique.
255 std::copy(rhs.begin(),rhs.end(),this->begin());
256 }
257
258 template <typename OPtr>
259 multi_array(const detail::multi_array::
260 const_sub_array<T,NumDims,OPtr>& rhs,
261 const general_storage_order<NumDims>& so = c_storage_order(),
262 const Allocator& alloc = Allocator())
263 : super_type(0,so,rhs.index_bases(),rhs.shape()),
264 alloc_base(boost::empty_init_t(),alloc)
265 {
266 allocate_space();
267 std::copy(rhs.begin(),rhs.end(),this->begin());
268 }
269
270
271 template <typename OPtr>
272 multi_array(const detail::multi_array::
273 const_multi_array_view<T,NumDims,OPtr>& rhs,
274 const general_storage_order<NumDims>& so = c_storage_order(),
275 const Allocator& alloc = Allocator())
276 : super_type(0,so,rhs.index_bases(),rhs.shape()),
277 alloc_base(boost::empty_init_t(),alloc)
278 {
279 allocate_space();
280 std::copy(rhs.begin(),rhs.end(),this->begin());
281 }
282
283#else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
284 // More limited support for MSVC
285
286
287 multi_array(const const_multi_array_ref<T,NumDims>& rhs,
288 const Allocator& alloc = Allocator())
289 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
290 alloc_base(boost::empty_init_t(),alloc)
291 {
292 allocate_space();
293 // Warning! storage order may change, hence the following copy technique.
294 std::copy(rhs.begin(),rhs.end(),this->begin());
295 }
296
297 multi_array(const const_multi_array_ref<T,NumDims>& rhs,
298 const general_storage_order<NumDims>& so,
299 const Allocator& alloc = Allocator())
300 : super_type(0,so,rhs.index_bases(),rhs.shape()),
301 alloc_base(boost::empty_init_t(),alloc)
302 {
303 allocate_space();
304 // Warning! storage order may change, hence the following copy technique.
305 std::copy(rhs.begin(),rhs.end(),this->begin());
306 }
307
308 multi_array(const detail::multi_array::
309 const_sub_array<T,NumDims>& rhs,
310 const Allocator& alloc = Allocator())
311 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
312 alloc_base(boost::empty_init_t(),alloc)
313 {
314 allocate_space();
315 std::copy(rhs.begin(),rhs.end(),this->begin());
316 }
317
318 multi_array(const detail::multi_array::
319 const_sub_array<T,NumDims>& rhs,
320 const general_storage_order<NumDims>& so,
321 const Allocator& alloc = Allocator())
322 : super_type(0,so,rhs.index_bases(),rhs.shape()),
323 alloc_base(boost::empty_init_t(),alloc)
324 {
325 allocate_space();
326 std::copy(rhs.begin(),rhs.end(),this->begin());
327 }
328
329
330 multi_array(const detail::multi_array::
331 const_multi_array_view<T,NumDims>& rhs,
332 const Allocator& alloc = Allocator())
333 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
334 alloc_base(boost::empty_init_t(),alloc)
335 {
336 allocate_space();
337 std::copy(rhs.begin(),rhs.end(),this->begin());
338 }
339
340 multi_array(const detail::multi_array::
341 const_multi_array_view<T,NumDims>& rhs,
342 const general_storage_order<NumDims>& so,
343 const Allocator& alloc = Allocator())
344 : super_type(0,so,rhs.index_bases(),rhs.shape()),
345 alloc_base(boost::empty_init_t(),alloc)
346 {
347 allocate_space();
348 std::copy(rhs.begin(),rhs.end(),this->begin());
349 }
350
351#endif // !BOOST_NO_FUNCTION_TEMPLATE_ORDERING
352
353 // Thes constructors are necessary because of more exact template matches.
354 multi_array(const multi_array_ref<T,NumDims>& rhs,
355 const Allocator& alloc = Allocator())
356 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
357 alloc_base(boost::empty_init_t(),alloc)
358 {
359 allocate_space();
360 // Warning! storage order may change, hence the following copy technique.
361 std::copy(rhs.begin(),rhs.end(),this->begin());
362 }
363
364 multi_array(const multi_array_ref<T,NumDims>& rhs,
365 const general_storage_order<NumDims>& so,
366 const Allocator& alloc = Allocator())
367 : super_type(0,so,rhs.index_bases(),rhs.shape()),
368 alloc_base(boost::empty_init_t(),alloc)
369 {
370 allocate_space();
371 // Warning! storage order may change, hence the following copy technique.
372 std::copy(rhs.begin(),rhs.end(),this->begin());
373 }
374
375
376 multi_array(const detail::multi_array::
377 sub_array<T,NumDims>& rhs,
378 const Allocator& alloc = Allocator())
379 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
380 alloc_base(boost::empty_init_t(),alloc)
381 {
382 allocate_space();
383 std::copy(rhs.begin(),rhs.end(),this->begin());
384 }
385
386 multi_array(const detail::multi_array::
387 sub_array<T,NumDims>& rhs,
388 const general_storage_order<NumDims>& so,
389 const Allocator& alloc = Allocator())
390 : super_type(0,so,rhs.index_bases(),rhs.shape()),
391 alloc_base(boost::empty_init_t(),alloc)
392 {
393 allocate_space();
394 std::copy(rhs.begin(),rhs.end(),this->begin());
395 }
396
397
398 multi_array(const detail::multi_array::
399 multi_array_view<T,NumDims>& rhs,
400 const Allocator& alloc = Allocator())
401 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()),
402 alloc_base(boost::empty_init_t(),alloc)
403 {
404 allocate_space();
405 std::copy(rhs.begin(),rhs.end(),this->begin());
406 }
407
408 multi_array(const detail::multi_array::
409 multi_array_view<T,NumDims>& rhs,
410 const general_storage_order<NumDims>& so,
411 const Allocator& alloc = Allocator())
412 : super_type(0,so,rhs.index_bases(),rhs.shape()),
413 alloc_base(boost::empty_init_t(),alloc)
414 {
415 allocate_space();
416 std::copy(rhs.begin(),rhs.end(),this->begin());
417 }
418
419 // Since assignment is a deep copy, multi_array_ref
420 // contains all the necessary code.
421 template <typename ConstMultiArray>
422 multi_array& operator=(const ConstMultiArray& other) {
423 super_type::operator=(other);
424 return *this;
425 }
426
427 multi_array& operator=(const multi_array& other) {
428 if (&other != this) {
429 super_type::operator=(other);
430 }
431 return *this;
432 }
433
434
435 template <typename ExtentList>
436 multi_array& resize(const ExtentList& extents) {
437 boost::function_requires<
438 detail::multi_array::CollectionConcept<ExtentList> >();
439
440 typedef detail::multi_array::extent_gen<NumDims> gen_type;
441 gen_type ranges;
442
443 for (int i=0; i != NumDims; ++i) {
444 typedef typename gen_type::range range_type;
445 ranges.ranges_[i] = range_type(0,extents[i]);
446 }
447
448 return this->resize(ranges);
449 }
450
451
452
453 multi_array& resize(const detail::multi_array
454 ::extent_gen<NumDims>& ranges) {
455
456
457 // build a multi_array with the specs given
458 multi_array new_array(ranges,this->storage_order(),allocator());
459
460
461 // build a view of tmp with the minimum extents
462
463 // Get the minimum extents of the arrays.
464 boost::array<size_type,NumDims> min_extents;
465
466 const size_type& (*min)(const size_type&, const size_type&) =
467 std::min;
468 std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(),
469 this->extent_list_.begin(),
470 min_extents.begin(),
471 min);
472
473
474 // typedef boost::array<index,NumDims> index_list;
475 // Build index_gen objects to create views with the same shape
476
477 // these need to be separate to handle non-zero index bases
478 typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen;
479 index_gen old_idxes;
480 index_gen new_idxes;
481
482 std::transform(new_array.index_base_list_.begin(),
483 new_array.index_base_list_.end(),
484 min_extents.begin(),new_idxes.ranges_.begin(),
485 detail::multi_array::populate_index_ranges());
486
487 std::transform(this->index_base_list_.begin(),
488 this->index_base_list_.end(),
489 min_extents.begin(),old_idxes.ranges_.begin(),
490 detail::multi_array::populate_index_ranges());
491
492 // Build same-shape views of the two arrays
493 typename
494 multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_old = (*this)[old_idxes];
495 typename
496 multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_new = new_array[new_idxes];
497
498 // Set the right portion of the new array
499 view_new = view_old;
500
501 using std::swap;
502 // Swap the internals of these arrays.
503 swap(this->super_type::base_,new_array.super_type::base_);
504 swap(this->allocator(),new_array.allocator());
505 swap(this->storage_,new_array.storage_);
506 swap(this->extent_list_,new_array.extent_list_);
507 swap(this->stride_list_,new_array.stride_list_);
508 swap(this->index_base_list_,new_array.index_base_list_);
509 swap(this->origin_offset_,new_array.origin_offset_);
510 swap(this->directional_offset_,new_array.directional_offset_);
511 swap(this->num_elements_,new_array.num_elements_);
512 swap(this->base_,new_array.base_);
513 swap(this->allocated_elements_,new_array.allocated_elements_);
514
515 return *this;
516 }
517
518
519 ~multi_array() {
520 deallocate_space();
521 }
522
523private:
524 friend inline bool operator==(const multi_array& a, const multi_array& b) {
525 return a.base() == b.base();
526 }
527
528 friend inline bool operator!=(const multi_array& a, const multi_array& b) {
529 return !(a == b);
530 }
531
532 const super_type& base() const {
533 return *this;
534 }
535
536 const Allocator& allocator() const {
537 return alloc_base::get();
538 }
539
540 Allocator& allocator() {
541 return alloc_base::get();
542 }
543
544 void allocate_space() {
545 base_ = allocator().allocate(this->num_elements());
546 this->set_base_ptr(base_);
547 allocated_elements_ = this->num_elements();
548 boost::alloc_construct_n(allocator(),base_,allocated_elements_);
549 }
550
551 void deallocate_space() {
552 if(base_) {
553 boost::alloc_destroy_n(allocator(),base_,allocated_elements_);
554 allocator().deallocate(base_,allocated_elements_);
555 }
556 }
557
558 typedef boost::array<size_type,NumDims> size_list;
559 typedef boost::array<index,NumDims> index_list;
560
561 T* base_;
562 size_type allocated_elements_;
563 enum {initial_base_ = 0};
564};
565
566} // namespace boost
567
568#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 406)
569# pragma GCC diagnostic pop
570#endif
571
572#endif
573

source code of boost/libs/multi_array/include/boost/multi_array.hpp