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_RG071801_HPP 17 #define BOOST_MULTI_ARRAY_RG071801_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/multi_array/allocators.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. operator ()boost::detail::multi_array::populate_index_ranges56 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 multi_array(const Allocator & alloc=Allocator ())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> multi_array(ExtentList const & extents,const Allocator & alloc=Allocator (),typename mpl::if_<detail::multi_array::is_multi_array_impl<ExtentList>,int &,int>::type * =0)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> multi_array(ExtentList const & extents,const general_storage_order<NumDims> & so)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> multi_array(ExtentList const & extents,const general_storage_order<NumDims> & so,Allocator const & alloc)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 multi_array(const detail::multi_array::extent_gen<NumDims> & ranges,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so)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 multi_array(const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so,Allocator const & alloc)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 multi_array(const multi_array & rhs)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> multi_array(const const_multi_array_ref<T,NumDims,OPtr> & rhs,const general_storage_order<NumDims> & so=c_storage_order (),const Allocator & alloc=Allocator ())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> multi_array(const detail::multi_array::const_sub_array<T,NumDims,OPtr> & rhs,const general_storage_order<NumDims> & so=c_storage_order (),const Allocator & alloc=Allocator ())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> multi_array(const detail::multi_array::const_multi_array_view<T,NumDims,OPtr> & rhs,const general_storage_order<NumDims> & so=c_storage_order (),const Allocator & alloc=Allocator ())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 multi_array(const const_multi_array_ref<T,NumDims> & rhs,const Allocator & alloc=Allocator ())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 multi_array(const const_multi_array_ref<T,NumDims> & rhs,const general_storage_order<NumDims> & so,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::const_sub_array<T,NumDims> & rhs,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::const_sub_array<T,NumDims> & rhs,const general_storage_order<NumDims> & so,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::const_multi_array_view<T,NumDims> & rhs,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::const_multi_array_view<T,NumDims> & rhs,const general_storage_order<NumDims> & so,const Allocator & alloc=Allocator ())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. multi_array(const multi_array_ref<T,NumDims> & rhs,const Allocator & alloc=Allocator ())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 multi_array(const multi_array_ref<T,NumDims> & rhs,const general_storage_order<NumDims> & so,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::sub_array<T,NumDims> & rhs,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::sub_array<T,NumDims> & rhs,const general_storage_order<NumDims> & so,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::multi_array_view<T,NumDims> & rhs,const Allocator & alloc=Allocator ())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 multi_array(const detail::multi_array::multi_array_view<T,NumDims> & rhs,const general_storage_order<NumDims> & so,const Allocator & alloc=Allocator ())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> operator =(const ConstMultiArray & other)422 multi_array& operator=(const ConstMultiArray& other) { 423 super_type::operator=(other); 424 return *this; 425 } 426 operator =(const multi_array & other)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> resize(const ExtentList & extents)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 resize(const detail::multi_array::extent_gen<NumDims> & ranges)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 ~multi_array()519 ~multi_array() { 520 deallocate_space(); 521 } 522 523 private: operator ==(const multi_array & a,const multi_array & b)524 friend inline bool operator==(const multi_array& a, const multi_array& b) { 525 return a.base() == b.base(); 526 } 527 operator !=(const multi_array & a,const multi_array & b)528 friend inline bool operator!=(const multi_array& a, const multi_array& b) { 529 return !(a == b); 530 } 531 base() const532 const super_type& base() const { 533 return *this; 534 } 535 allocator() const536 const Allocator& allocator() const { 537 return alloc_base::get(); 538 } 539 allocator()540 Allocator& allocator() { 541 return alloc_base::get(); 542 } 543 allocate_space()544 void allocate_space() { 545 base_ = allocator().allocate(this->num_elements()); 546 this->set_base_ptr(base_); 547 allocated_elements_ = this->num_elements(); 548 detail::multi_array::construct(allocator(),base_,base_+allocated_elements_); 549 } 550 deallocate_space()551 void deallocate_space() { 552 if(base_) { 553 detail::multi_array::destroy(allocator(),base_,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 // BOOST_MULTI_ARRAY_RG071801_HPP 573