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_REF_RG071801_HPP 14 #define BOOST_MULTI_ARRAY_REF_RG071801_HPP 15 16 // 17 // multi_array_ref.hpp - code for creating "views" of array data. 18 // 19 20 #include "boost/multi_array/base.hpp" 21 #include "boost/multi_array/collection_concept.hpp" 22 #include "boost/multi_array/concept_checks.hpp" 23 #include "boost/multi_array/iterator.hpp" 24 #include "boost/multi_array/storage_order.hpp" 25 #include "boost/multi_array/subarray.hpp" 26 #include "boost/multi_array/view.hpp" 27 #include "boost/multi_array/algorithm.hpp" 28 #include "boost/array.hpp" 29 #include "boost/concept_check.hpp" 30 #include "boost/functional.hpp" 31 #include "boost/limits.hpp" 32 #include <algorithm> 33 #include <cassert> 34 #include <cstddef> 35 #include <functional> 36 #include <numeric> 37 38 namespace boost { 39 40 template <typename T, std::size_t NumDims, 41 typename TPtr = const T* 42 > 43 class const_multi_array_ref : 44 public detail::multi_array::multi_array_impl_base<T,NumDims> 45 { 46 typedef detail::multi_array::multi_array_impl_base<T,NumDims> super_type; 47 public: 48 typedef typename super_type::value_type value_type; 49 typedef typename super_type::const_reference const_reference; 50 typedef typename super_type::const_iterator const_iterator; 51 typedef typename super_type::const_reverse_iterator const_reverse_iterator; 52 typedef typename super_type::element element; 53 typedef typename super_type::size_type size_type; 54 typedef typename super_type::difference_type difference_type; 55 typedef typename super_type::index index; 56 typedef typename super_type::extent_range extent_range; 57 typedef general_storage_order<NumDims> storage_order_type; 58 59 // template typedefs 60 template <std::size_t NDims> 61 struct const_array_view { 62 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; 63 }; 64 65 template <std::size_t NDims> 66 struct array_view { 67 typedef boost::detail::multi_array::multi_array_view<T,NDims> type; 68 }; 69 70 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 71 // make const_multi_array_ref a friend of itself 72 template <typename,std::size_t,typename> 73 friend class const_multi_array_ref; 74 #endif 75 76 // This ensures that const_multi_array_ref types with different TPtr 77 // types can convert to each other 78 template <typename OPtr> const_multi_array_ref(const const_multi_array_ref<T,NumDims,OPtr> & other)79 const_multi_array_ref(const const_multi_array_ref<T,NumDims,OPtr>& other) 80 : base_(other.base_), storage_(other.storage_), 81 extent_list_(other.extent_list_), 82 stride_list_(other.stride_list_), 83 index_base_list_(other.index_base_list_), 84 origin_offset_(other.origin_offset_), 85 directional_offset_(other.directional_offset_), 86 num_elements_(other.num_elements_) { } 87 88 template <typename ExtentList> const_multi_array_ref(TPtr base,const ExtentList & extents)89 explicit const_multi_array_ref(TPtr base, const ExtentList& extents) : 90 base_(base), storage_(c_storage_order()) { 91 boost::function_requires< 92 detail::multi_array::CollectionConcept<ExtentList> >(); 93 94 index_base_list_.assign(0); 95 init_multi_array_ref(extents.begin()); 96 } 97 98 template <typename ExtentList> const_multi_array_ref(TPtr base,const ExtentList & extents,const general_storage_order<NumDims> & so)99 explicit const_multi_array_ref(TPtr base, const ExtentList& extents, 100 const general_storage_order<NumDims>& so) : 101 base_(base), storage_(so) { 102 boost::function_requires< 103 detail::multi_array::CollectionConcept<ExtentList> >(); 104 105 index_base_list_.assign(0); 106 init_multi_array_ref(extents.begin()); 107 } 108 const_multi_array_ref(TPtr base,const detail::multi_array::extent_gen<NumDims> & ranges)109 explicit const_multi_array_ref(TPtr base, 110 const detail::multi_array:: 111 extent_gen<NumDims>& ranges) : 112 base_(base), storage_(c_storage_order()) { 113 114 init_from_extent_gen(ranges); 115 } 116 const_multi_array_ref(TPtr base,const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so)117 explicit const_multi_array_ref(TPtr base, 118 const detail::multi_array:: 119 extent_gen<NumDims>& ranges, 120 const general_storage_order<NumDims>& so) : 121 base_(base), storage_(so) { 122 123 init_from_extent_gen(ranges); 124 } 125 126 template <class InputIterator> assign(InputIterator begin,InputIterator end)127 void assign(InputIterator begin, InputIterator end) { 128 boost::function_requires<InputIteratorConcept<InputIterator> >(); 129 130 InputIterator in_iter = begin; 131 T* out_iter = base_; 132 std::size_t copy_count=0; 133 while (in_iter != end && copy_count < num_elements_) { 134 *out_iter++ = *in_iter++; 135 copy_count++; 136 } 137 } 138 139 template <class BaseList> reindex(const BaseList & values)140 void reindex(const BaseList& values) { 141 boost::function_requires< 142 detail::multi_array::CollectionConcept<BaseList> >(); 143 boost::detail::multi_array:: 144 copy_n(values.begin(),num_dimensions(),index_base_list_.begin()); 145 origin_offset_ = 146 this->calculate_origin_offset(stride_list_,extent_list_, 147 storage_,index_base_list_); 148 } 149 reindex(index value)150 void reindex(index value) { 151 index_base_list_.assign(value); 152 origin_offset_ = 153 this->calculate_origin_offset(stride_list_,extent_list_, 154 storage_,index_base_list_); 155 } 156 157 template <typename SizeList> reshape(const SizeList & extents)158 void reshape(const SizeList& extents) { 159 boost::function_requires< 160 detail::multi_array::CollectionConcept<SizeList> >(); 161 assert(num_elements_ == 162 std::accumulate(extents.begin(),extents.end(), 163 size_type(1),std::multiplies<size_type>())); 164 165 std::copy(extents.begin(),extents.end(),extent_list_.begin()); 166 this->compute_strides(stride_list_,extent_list_,storage_); 167 168 origin_offset_ = 169 this->calculate_origin_offset(stride_list_,extent_list_, 170 storage_,index_base_list_); 171 } 172 num_dimensions() const173 size_type num_dimensions() const { return NumDims; } 174 size() const175 size_type size() const { return extent_list_.front(); } 176 177 // given reshaping functionality, this is the max possible size. max_size() const178 size_type max_size() const { return num_elements(); } 179 empty() const180 bool empty() const { return size() == 0; } 181 shape() const182 const size_type* shape() const { 183 return extent_list_.data(); 184 } 185 strides() const186 const index* strides() const { 187 return stride_list_.data(); 188 } 189 origin() const190 const element* origin() const { return base_+origin_offset_; } data() const191 const element* data() const { return base_; } 192 num_elements() const193 size_type num_elements() const { return num_elements_; } 194 index_bases() const195 const index* index_bases() const { 196 return index_base_list_.data(); 197 } 198 199 storage_order() const200 const storage_order_type& storage_order() const { 201 return storage_; 202 } 203 204 template <typename IndexList> operator ()(IndexList indices) const205 const element& operator()(IndexList indices) const { 206 boost::function_requires< 207 detail::multi_array::CollectionConcept<IndexList> >(); 208 return super_type::access_element(boost::type<const element&>(), 209 origin(), 210 indices,strides()); 211 } 212 213 // Only allow const element access operator [](index idx) const214 const_reference operator[](index idx) const { 215 return super_type::access(boost::type<const_reference>(), 216 idx,origin(), 217 shape(),strides(),index_bases()); 218 } 219 220 // see generate_array_view in base.hpp 221 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 222 template <int NDims> 223 #else 224 template <int NumDims, int NDims> // else ICE 225 #endif // BOOST_MSVC 226 typename const_array_view<NDims>::type operator [](const detail::multi_array::index_gen<NumDims,NDims> & indices) const227 operator[](const detail::multi_array:: 228 index_gen<NumDims,NDims>& indices) 229 const { 230 typedef typename const_array_view<NDims>::type return_type; 231 return 232 super_type::generate_array_view(boost::type<return_type>(), 233 indices, 234 shape(), 235 strides(), 236 index_bases(), 237 origin()); 238 } 239 begin() const240 const_iterator begin() const { 241 return const_iterator(*index_bases(),origin(), 242 shape(),strides(),index_bases()); 243 } 244 end() const245 const_iterator end() const { 246 return const_iterator(*index_bases()+(index)*shape(),origin(), 247 shape(),strides(),index_bases()); 248 } 249 rbegin() const250 const_reverse_iterator rbegin() const { 251 return const_reverse_iterator(end()); 252 } 253 rend() const254 const_reverse_iterator rend() const { 255 return const_reverse_iterator(begin()); 256 } 257 258 259 template <typename OPtr> operator ==(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const260 bool operator==(const 261 const_multi_array_ref<T,NumDims,OPtr>& rhs) 262 const { 263 if(std::equal(extent_list_.begin(), 264 extent_list_.end(), 265 rhs.extent_list_.begin())) 266 return std::equal(begin(),end(),rhs.begin()); 267 else return false; 268 } 269 270 template <typename OPtr> operator <(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const271 bool operator<(const 272 const_multi_array_ref<T,NumDims,OPtr>& rhs) 273 const { 274 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end()); 275 } 276 277 template <typename OPtr> operator !=(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const278 bool operator!=(const 279 const_multi_array_ref<T,NumDims,OPtr>& rhs) 280 const { 281 return !(*this == rhs); 282 } 283 284 template <typename OPtr> operator >(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const285 bool operator>(const 286 const_multi_array_ref<T,NumDims,OPtr>& rhs) 287 const { 288 return rhs < *this; 289 } 290 291 template <typename OPtr> operator <=(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const292 bool operator<=(const 293 const_multi_array_ref<T,NumDims,OPtr>& rhs) 294 const { 295 return !(*this > rhs); 296 } 297 298 template <typename OPtr> operator >=(const const_multi_array_ref<T,NumDims,OPtr> & rhs) const299 bool operator>=(const 300 const_multi_array_ref<T,NumDims,OPtr>& rhs) 301 const { 302 return !(*this < rhs); 303 } 304 305 306 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 307 protected: 308 #else 309 public: 310 #endif 311 312 typedef boost::array<size_type,NumDims> size_list; 313 typedef boost::array<index,NumDims> index_list; 314 315 // This is used by multi_array, which is a subclass of this set_base_ptr(TPtr new_base)316 void set_base_ptr(TPtr new_base) { base_ = new_base; } 317 318 319 // This constructor supports multi_array's default constructor 320 // and constructors from multi_array_ref, subarray, and array_view 321 explicit const_multi_array_ref(TPtr base,const storage_order_type & so,const index * index_bases,const size_type * extents)322 const_multi_array_ref(TPtr base, 323 const storage_order_type& so, 324 const index * index_bases, 325 const size_type* extents) : 326 base_(base), storage_(so), origin_offset_(0), directional_offset_(0) 327 { 328 // If index_bases or extents is null, then initialize the corresponding 329 // private data to zeroed lists. 330 if(index_bases) { 331 boost::detail::multi_array:: 332 copy_n(index_bases,NumDims,index_base_list_.begin()); 333 } else { 334 std::fill_n(index_base_list_.begin(),NumDims,0); 335 } 336 if(extents) { 337 init_multi_array_ref(extents); 338 } else { 339 boost::array<index,NumDims> extent_list; 340 extent_list.assign(0); 341 init_multi_array_ref(extent_list.begin()); 342 } 343 } 344 345 346 TPtr base_; 347 storage_order_type storage_; 348 size_list extent_list_; 349 index_list stride_list_; 350 index_list index_base_list_; 351 index origin_offset_; 352 index directional_offset_; 353 size_type num_elements_; 354 355 private: 356 // const_multi_array_ref cannot be assigned to (no deep copies!) 357 const_multi_array_ref& operator=(const const_multi_array_ref& other); 358 init_from_extent_gen(const detail::multi_array::extent_gen<NumDims> & ranges)359 void init_from_extent_gen(const 360 detail::multi_array:: 361 extent_gen<NumDims>& ranges) { 362 363 typedef boost::array<index,NumDims> extent_list; 364 365 // get the index_base values 366 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(), 367 index_base_list_.begin(), 368 boost::mem_fun_ref(&extent_range::start)); 369 370 // calculate the extents 371 extent_list extents; 372 std::transform(ranges.ranges_.begin(),ranges.ranges_.end(), 373 extents.begin(), 374 boost::mem_fun_ref(&extent_range::size)); 375 376 init_multi_array_ref(extents.begin()); 377 } 378 379 380 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 381 protected: 382 #else 383 public: 384 #endif 385 // RG - move me! 386 template <class InputIterator> init_multi_array_ref(InputIterator extents_iter)387 void init_multi_array_ref(InputIterator extents_iter) { 388 boost::function_requires<InputIteratorConcept<InputIterator> >(); 389 390 boost::detail::multi_array:: 391 copy_n(extents_iter,num_dimensions(),extent_list_.begin()); 392 393 // Calculate the array size 394 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(), 395 size_type(1),std::multiplies<size_type>()); 396 397 this->compute_strides(stride_list_,extent_list_,storage_); 398 399 origin_offset_ = 400 this->calculate_origin_offset(stride_list_,extent_list_, 401 storage_,index_base_list_); 402 directional_offset_ = 403 this->calculate_descending_dimension_offset(stride_list_,extent_list_, 404 storage_); 405 } 406 }; 407 408 template <typename T, std::size_t NumDims> 409 class multi_array_ref : 410 public const_multi_array_ref<T,NumDims,T*> 411 { 412 typedef const_multi_array_ref<T,NumDims,T*> super_type; 413 public: 414 typedef typename super_type::value_type value_type; 415 typedef typename super_type::reference reference; 416 typedef typename super_type::iterator iterator; 417 typedef typename super_type::reverse_iterator reverse_iterator; 418 typedef typename super_type::const_reference const_reference; 419 typedef typename super_type::const_iterator const_iterator; 420 typedef typename super_type::const_reverse_iterator const_reverse_iterator; 421 typedef typename super_type::element element; 422 typedef typename super_type::size_type size_type; 423 typedef typename super_type::difference_type difference_type; 424 typedef typename super_type::index index; 425 typedef typename super_type::extent_range extent_range; 426 427 typedef typename super_type::storage_order_type storage_order_type; 428 typedef typename super_type::index_list index_list; 429 typedef typename super_type::size_list size_list; 430 431 template <std::size_t NDims> 432 struct const_array_view { 433 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; 434 }; 435 436 template <std::size_t NDims> 437 struct array_view { 438 typedef boost::detail::multi_array::multi_array_view<T,NDims> type; 439 }; 440 441 template <class ExtentList> multi_array_ref(T * base,const ExtentList & extents)442 explicit multi_array_ref(T* base, const ExtentList& extents) : 443 super_type(base,extents) { 444 boost::function_requires< 445 detail::multi_array::CollectionConcept<ExtentList> >(); 446 } 447 448 template <class ExtentList> multi_array_ref(T * base,const ExtentList & extents,const general_storage_order<NumDims> & so)449 explicit multi_array_ref(T* base, const ExtentList& extents, 450 const general_storage_order<NumDims>& so) : 451 super_type(base,extents,so) { 452 boost::function_requires< 453 detail::multi_array::CollectionConcept<ExtentList> >(); 454 } 455 456 multi_array_ref(T * base,const detail::multi_array::extent_gen<NumDims> & ranges)457 explicit multi_array_ref(T* base, 458 const detail::multi_array:: 459 extent_gen<NumDims>& ranges) : 460 super_type(base,ranges) { } 461 462 multi_array_ref(T * base,const detail::multi_array::extent_gen<NumDims> & ranges,const general_storage_order<NumDims> & so)463 explicit multi_array_ref(T* base, 464 const detail::multi_array:: 465 extent_gen<NumDims>& 466 ranges, 467 const general_storage_order<NumDims>& so) : 468 super_type(base,ranges,so) { } 469 470 471 // Assignment from other ConstMultiArray types. 472 template <typename ConstMultiArray> operator =(const ConstMultiArray & other)473 multi_array_ref& operator=(const ConstMultiArray& other) { 474 function_requires< 475 detail::multi_array:: 476 ConstMultiArrayConcept<ConstMultiArray,NumDims> >(); 477 478 // make sure the dimensions agree 479 assert(other.num_dimensions() == this->num_dimensions()); 480 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(), 481 this->shape())); 482 // iterator-based copy 483 std::copy(other.begin(),other.end(),this->begin()); 484 return *this; 485 } 486 operator =(const multi_array_ref & other)487 multi_array_ref& operator=(const multi_array_ref& other) { 488 if (&other != this) { 489 // make sure the dimensions agree 490 491 assert(other.num_dimensions() == this->num_dimensions()); 492 assert(std::equal(other.shape(),other.shape()+this->num_dimensions(), 493 this->shape())); 494 // iterator-based copy 495 std::copy(other.begin(),other.end(),this->begin()); 496 } 497 return *this; 498 } 499 origin()500 element* origin() { return super_type::base_+super_type::origin_offset_; } 501 data()502 element* data() { return super_type::base_; } 503 504 template <class IndexList> operator ()(const IndexList & indices)505 element& operator()(const IndexList& indices) { 506 boost::function_requires< 507 detail::multi_array::CollectionConcept<IndexList> >(); 508 return super_type::access_element(boost::type<element&>(), 509 origin(), 510 indices,this->strides()); 511 } 512 513 operator [](index idx)514 reference operator[](index idx) { 515 return super_type::access(boost::type<reference>(), 516 idx,origin(), 517 this->shape(),this->strides(), 518 this->index_bases()); 519 } 520 521 522 // See note attached to generate_array_view in base.hpp 523 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 524 template <int NDims> 525 #else 526 template <int NumDims, int NDims> // else ICE 527 #endif // BOOST_MSVC 528 typename array_view<NDims>::type operator [](const detail::multi_array::index_gen<NumDims,NDims> & indices)529 operator[](const detail::multi_array:: 530 index_gen<NumDims,NDims>& indices) { 531 typedef typename array_view<NDims>::type return_type; 532 return 533 super_type::generate_array_view(boost::type<return_type>(), 534 indices, 535 this->shape(), 536 this->strides(), 537 this->index_bases(), 538 origin()); 539 } 540 541 begin()542 iterator begin() { 543 return iterator(*this->index_bases(),origin(),this->shape(), 544 this->strides(),this->index_bases()); 545 } 546 end()547 iterator end() { 548 return iterator(*this->index_bases()+(index)*this->shape(),origin(), 549 this->shape(),this->strides(), 550 this->index_bases()); 551 } 552 553 // rbegin() and rend() written naively to thwart MSVC ICE. rbegin()554 reverse_iterator rbegin() { 555 reverse_iterator ri(end()); 556 return ri; 557 } 558 rend()559 reverse_iterator rend() { 560 reverse_iterator ri(begin()); 561 return ri; 562 } 563 564 // Using declarations don't seem to work for g++ 565 // These are the proxies to work around this. 566 origin() const567 const element* origin() const { return super_type::origin(); } data() const568 const element* data() const { return super_type::data(); } 569 570 template <class IndexList> operator ()(const IndexList & indices) const571 const element& operator()(const IndexList& indices) const { 572 boost::function_requires< 573 detail::multi_array::CollectionConcept<IndexList> >(); 574 return super_type::operator()(indices); 575 } 576 operator [](index idx) const577 const_reference operator[](index idx) const { 578 return super_type::access(boost::type<const_reference>(), 579 idx,origin(), 580 this->shape(),this->strides(), 581 this->index_bases()); 582 } 583 584 // See note attached to generate_array_view in base.hpp 585 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 586 template <int NDims> 587 #else 588 template <int NumDims, int NDims> // else ICE 589 #endif // BOOST_MSVC 590 typename const_array_view<NDims>::type operator [](const detail::multi_array::index_gen<NumDims,NDims> & indices) const591 operator[](const detail::multi_array:: 592 index_gen<NumDims,NDims>& indices) 593 const { 594 return super_type::operator[](indices); 595 } 596 begin() const597 const_iterator begin() const { 598 return super_type::begin(); 599 } 600 end() const601 const_iterator end() const { 602 return super_type::end(); 603 } 604 rbegin() const605 const_reverse_iterator rbegin() const { 606 return super_type::rbegin(); 607 } 608 rend() const609 const_reverse_iterator rend() const { 610 return super_type::rend(); 611 } 612 613 protected: 614 // This is only supplied to support multi_array's default constructor multi_array_ref(T * base,const storage_order_type & so,const index * index_bases,const size_type * extents)615 explicit multi_array_ref(T* base, 616 const storage_order_type& so, 617 const index* index_bases, 618 const size_type* extents) : 619 super_type(base,so,index_bases,extents) { } 620 621 }; 622 623 } // namespace boost 624 625 #endif // BOOST_MULTI_ARRAY_REF_RG071801_HPP 626