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