1 // Copyright 2002 The Trustees of Indiana University. 2 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) 6 7 // Boost.MultiArray Library 8 // Authors: Ronald Garcia 9 // Jeremy Siek 10 // Andrew Lumsdaine 11 // See http://www.boost.org/libs/multi_array for documentation. 12 13 #ifndef BOOST_MULTI_ARRAY_RG071801_HPP 14 #define BOOST_MULTI_ARRAY_RG071801_HPP 15 16 // 17 // multi_array.hpp - contains the multi_array class template 18 // declaration and definition 19 // 20 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" 31 #include <algorithm> 32 #include <cstddef> 33 #include <functional> 34 #include <numeric> 35 #include <vector> 36 37 38 39 namespace boost { 40 namespace detail { 41 namespace multi_array { 42 43 struct populate_index_ranges { 44 multi_array_types::index_range 45 // RG: underscore on extent_ to stifle strange MSVC warning. operator ()boost::detail::multi_array::populate_index_ranges46 operator()(multi_array_types::index base, 47 multi_array_types::size_type extent_) { 48 return multi_array_types::index_range(base,base+extent_); 49 } 50 }; 51 52 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING 53 // 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. 58 // 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>&); 65 66 char ( &is_multi_array_impl_help(...) )[2]; 67 68 template <class T> 69 struct is_multi_array_impl 70 { 71 static T x; 72 BOOST_STATIC_CONSTANT(bool, value = sizeof((is_multi_array_impl_help)(x)) == 1); 73 74 typedef mpl::bool_<value> type; 75 }; 76 77 template <bool multi_array = false> 78 struct disable_multi_array_impl_impl 79 { 80 typedef int type; 81 }; 82 83 template <> 84 struct disable_multi_array_impl_impl<true> 85 { 86 // forming a pointer to a reference triggers SFINAE 87 typedef int& type; 88 }; 89 90 91 template <class T> 92 struct disable_multi_array_impl : 93 disable_multi_array_impl_impl<is_multi_array_impl<T>::value> 94 { }; 95 96 97 template <> 98 struct disable_multi_array_impl<int> 99 { 100 typedef int type; 101 }; 102 103 104 #endif 105 106 } //namespace multi_array 107 } // namespace detail 108 109 template<typename T, std::size_t NumDims, 110 typename Allocator> 111 class multi_array : 112 public multi_array_ref<T,NumDims> 113 { 114 typedef multi_array_ref<T,NumDims> super_type; 115 public: 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; 128 129 130 template <std::size_t NDims> 131 struct const_array_view { 132 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; 133 }; 134 135 template <std::size_t NDims> 136 struct array_view { 137 typedef boost::detail::multi_array::multi_array_view<T,NDims> type; 138 }; 139 multi_array()140 explicit multi_array() : 141 super_type((T*)initial_base_,c_storage_order(), 142 /*index_bases=*/0, /*extents=*/0) { 143 allocate_space(); 144 } 145 146 template <class ExtentList> multi_array(ExtentList const & extents,typename mpl::if_<detail::multi_array::is_multi_array_impl<ExtentList>,int &,int>::type * =0)147 explicit multi_array( 148 ExtentList const& extents 149 #ifdef BOOST_NO_FUNCTION_TEMPLATE_ORDERING 150 , typename mpl::if_< 151 detail::multi_array::is_multi_array_impl<ExtentList>, 152 int&,int>::type* = 0 153 #endif 154 ) : 155 super_type((T*)initial_base_,extents) { 156 boost::function_requires< 157 detail::multi_array::CollectionConcept<ExtentList> >(); 158 allocate_space(); 159 } 160 161 162 template <class ExtentList> multi_array(ExtentList const & extents,const general_storage_order<NumDims> & so)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> >(); 168 allocate_space(); 169 } 170 171 template <class ExtentList> multi_array(ExtentList const & extents,const general_storage_order<NumDims> & so,Allocator const & alloc)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> >(); 178 allocate_space(); 179 } 180 181 multi_array(const detail::multi_array::extent_gen<NumDims> & ranges)182 explicit multi_array(const detail::multi_array 183 ::extent_gen<NumDims>& ranges) : 184 super_type((T*)initial_base_,ranges) { 185 186 allocate_space(); 187 } 188 189 multi_array(const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so)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) { 194 195 allocate_space(); 196 } 197 198 multi_array(const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so,Allocator const & alloc)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) { 204 205 allocate_space(); 206 } 207 multi_array(const multi_array & rhs)208 multi_array(const multi_array& rhs) : 209 super_type(rhs), allocator_(rhs.allocator_) { 210 allocate_space(); 211 boost::detail::multi_array::copy_n(rhs.base_,rhs.num_elements(),base_); 212 } 213 214 215 // 216 // A multi_array is constructible from any multi_array_ref, subarray, or 217 // array_view object. The following constructors ensure that. 218 // 219 220 // Due to limited support for partial template ordering, 221 // MSVC 6&7 confuse the following with the most basic ExtentList 222 // constructor. 223 #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING 224 template <typename OPtr> multi_array(const const_multi_array_ref<T,NumDims,OPtr> & rhs,const general_storage_order<NumDims> & so=c_storage_order ())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()) 228 { 229 allocate_space(); 230 // Warning! storage order may change, hence the following copy technique. 231 std::copy(rhs.begin(),rhs.end(),this->begin()); 232 } 233 234 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 ())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()) 239 { 240 allocate_space(); 241 std::copy(rhs.begin(),rhs.end(),this->begin()); 242 } 243 244 245 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 ())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()) 250 { 251 allocate_space(); 252 std::copy(rhs.begin(),rhs.end(),this->begin()); 253 } 254 255 #else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING 256 // More limited support for MSVC 257 258 multi_array(const const_multi_array_ref<T,NumDims> & rhs)259 multi_array(const const_multi_array_ref<T,NumDims>& rhs) 260 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 261 { 262 allocate_space(); 263 // Warning! storage order may change, hence the following copy technique. 264 std::copy(rhs.begin(),rhs.end(),this->begin()); 265 } 266 multi_array(const const_multi_array_ref<T,NumDims> & rhs,const general_storage_order<NumDims> & so)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()) 270 { 271 allocate_space(); 272 // Warning! storage order may change, hence the following copy technique. 273 std::copy(rhs.begin(),rhs.end(),this->begin()); 274 } 275 multi_array(const detail::multi_array::const_sub_array<T,NumDims> & rhs)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()) 279 { 280 allocate_space(); 281 std::copy(rhs.begin(),rhs.end(),this->begin()); 282 } 283 multi_array(const detail::multi_array::const_sub_array<T,NumDims> & rhs,const general_storage_order<NumDims> & so)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()) 288 { 289 allocate_space(); 290 std::copy(rhs.begin(),rhs.end(),this->begin()); 291 } 292 293 multi_array(const detail::multi_array::const_multi_array_view<T,NumDims> & rhs)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()) 297 { 298 allocate_space(); 299 std::copy(rhs.begin(),rhs.end(),this->begin()); 300 } 301 multi_array(const detail::multi_array::const_multi_array_view<T,NumDims> & rhs,const general_storage_order<NumDims> & so)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()) 306 { 307 allocate_space(); 308 std::copy(rhs.begin(),rhs.end(),this->begin()); 309 } 310 311 #endif // !BOOST_NO_FUNCTION_TEMPLATE_ORDERING 312 313 // Thes constructors are necessary because of more exact template matches. multi_array(const multi_array_ref<T,NumDims> & rhs)314 multi_array(const multi_array_ref<T,NumDims>& rhs) 315 : super_type(0,c_storage_order(),rhs.index_bases(),rhs.shape()) 316 { 317 allocate_space(); 318 // Warning! storage order may change, hence the following copy technique. 319 std::copy(rhs.begin(),rhs.end(),this->begin()); 320 } 321 multi_array(const multi_array_ref<T,NumDims> & rhs,const general_storage_order<NumDims> & so)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()) 325 { 326 allocate_space(); 327 // Warning! storage order may change, hence the following copy technique. 328 std::copy(rhs.begin(),rhs.end(),this->begin()); 329 } 330 331 multi_array(const detail::multi_array::sub_array<T,NumDims> & rhs)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()) 335 { 336 allocate_space(); 337 std::copy(rhs.begin(),rhs.end(),this->begin()); 338 } 339 multi_array(const detail::multi_array::sub_array<T,NumDims> & rhs,const general_storage_order<NumDims> & so)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()) 344 { 345 allocate_space(); 346 std::copy(rhs.begin(),rhs.end(),this->begin()); 347 } 348 349 multi_array(const detail::multi_array::multi_array_view<T,NumDims> & rhs)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()) 353 { 354 allocate_space(); 355 std::copy(rhs.begin(),rhs.end(),this->begin()); 356 } 357 multi_array(const detail::multi_array::multi_array_view<T,NumDims> & rhs,const general_storage_order<NumDims> & so)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()) 362 { 363 allocate_space(); 364 std::copy(rhs.begin(),rhs.end(),this->begin()); 365 } 366 367 // Since assignment is a deep copy, multi_array_ref 368 // contains all the necessary code. 369 template <typename ConstMultiArray> operator =(const ConstMultiArray & other)370 multi_array& operator=(const ConstMultiArray& other) { 371 super_type::operator=(other); 372 return *this; 373 } 374 operator =(const multi_array & other)375 multi_array& operator=(const multi_array& other) { 376 if (&other != this) { 377 super_type::operator=(other); 378 } 379 return *this; 380 } 381 382 383 template <typename ExtentList> resize(const ExtentList & extents)384 multi_array& resize(const ExtentList& extents) { 385 boost::function_requires< 386 detail::multi_array::CollectionConcept<ExtentList> >(); 387 388 typedef detail::multi_array::extent_gen<NumDims> gen_type; 389 gen_type ranges; 390 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]); 394 } 395 396 return this->resize(ranges); 397 } 398 399 400 resize(const detail::multi_array::extent_gen<NumDims> & ranges)401 multi_array& resize(const detail::multi_array 402 ::extent_gen<NumDims>& ranges) { 403 404 405 // build a multi_array with the specs given 406 multi_array new_array(ranges,this->storage_order()); 407 408 409 // build a view of tmp with the minimum extents 410 411 // Get the minimum extents of the arrays. 412 boost::array<size_type,NumDims> min_extents; 413 414 const size_type& (*min)(const size_type&, const size_type&) = 415 std::min; 416 std::transform(new_array.extent_list_.begin(),new_array.extent_list_.end(), 417 this->extent_list_.begin(), 418 min_extents.begin(), 419 min); 420 421 422 // typedef boost::array<index,NumDims> index_list; 423 // Build index_gen objects to create views with the same shape 424 425 // these need to be separate to handle non-zero index bases 426 typedef detail::multi_array::index_gen<NumDims,NumDims> index_gen; 427 index_gen old_idxes; 428 index_gen new_idxes; 429 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()); 434 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()); 439 440 // Build same-shape views of the two arrays 441 typename 442 multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_old = (*this)[old_idxes]; 443 typename 444 multi_array::BOOST_NESTED_TEMPLATE array_view<NumDims>::type view_new = new_array[new_idxes]; 445 446 // Set the right portion of the new array 447 view_new = view_old; 448 449 using std::swap; 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_); 462 463 return *this; 464 } 465 466 ~multi_array()467 ~multi_array() { 468 deallocate_space(); 469 } 470 471 private: allocate_space()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()); 478 } 479 deallocate_space()480 void deallocate_space() { 481 if(base_) { 482 for(T* i = base_; i != base_+allocated_elements_; ++i) 483 allocator_.destroy(i); 484 allocator_.deallocate(base_,allocated_elements_); 485 } 486 } 487 488 typedef boost::array<size_type,NumDims> size_list; 489 typedef boost::array<index,NumDims> index_list; 490 491 Allocator allocator_; 492 T* base_; 493 size_type allocated_elements_; 494 enum {initial_base_ = 0}; 495 }; 496 497 } // namespace boost 498 499 #endif // BOOST_MULTI_ARRAY_RG071801_HPP 500