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 | |
49 | namespace 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 | // |
69 | template <typename T, std::size_t NumDims, typename TPtr> |
70 | char is_multi_array_impl_help(const_multi_array_view<T,NumDims,TPtr>&); |
71 | template <typename T, std::size_t NumDims, typename TPtr> |
72 | char is_multi_array_impl_help(const_sub_array<T,NumDims,TPtr>&); |
73 | template <typename T, std::size_t NumDims, typename TPtr> |
74 | char is_multi_array_impl_help(const_multi_array_ref<T,NumDims,TPtr>&); |
75 | |
76 | char ( &is_multi_array_impl_help(...) )[2]; |
77 | |
78 | template <class T> |
79 | struct 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 | |
87 | template <bool multi_array = false> |
88 | struct disable_multi_array_impl_impl |
89 | { |
90 | typedef int type; |
91 | }; |
92 | |
93 | template <> |
94 | struct disable_multi_array_impl_impl<true> |
95 | { |
96 | // forming a pointer to a reference triggers SFINAE |
97 | typedef int& type; |
98 | }; |
99 | |
100 | |
101 | template <class T> |
102 | struct disable_multi_array_impl : |
103 | disable_multi_array_impl_impl<is_multi_array_impl<T>::value> |
104 | { }; |
105 | |
106 | |
107 | template <> |
108 | struct disable_multi_array_impl<int> |
109 | { |
110 | typedef int type; |
111 | }; |
112 | |
113 | |
114 | #endif |
115 | |
116 | } //namespace multi_array |
117 | } // namespace detail |
118 | |
119 | template<typename T, std::size_t NumDims, |
120 | typename Allocator> |
121 | class 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; |
127 | public: |
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 | |
523 | private: |
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 | |