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_VIEW_HPP 14 #define BOOST_MULTI_ARRAY_VIEW_HPP 15 16 // 17 // view.hpp - code for creating "views" of array data. 18 // 19 20 #include "boost/multi_array/base.hpp" 21 #include "boost/multi_array/concept_checks.hpp" 22 #include "boost/multi_array/iterator.hpp" 23 #include "boost/multi_array/storage_order.hpp" 24 #include "boost/multi_array/subarray.hpp" 25 #include "boost/multi_array/algorithm.hpp" 26 #include "boost/type_traits/is_integral.hpp" 27 #include "boost/utility/enable_if.hpp" 28 #include "boost/array.hpp" 29 #include "boost/limits.hpp" 30 #include <algorithm> 31 #include <cstddef> 32 #include <functional> 33 #include <numeric> 34 35 namespace boost { 36 namespace detail { 37 namespace multi_array { 38 39 // TPtr = const T* defaulted in base.hpp 40 template <typename T, std::size_t NumDims, typename TPtr> 41 class const_multi_array_view : 42 public boost::detail::multi_array::multi_array_impl_base<T,NumDims> 43 { 44 typedef boost::detail::multi_array::multi_array_impl_base<T,NumDims> super_type; 45 public: 46 typedef typename super_type::value_type value_type; 47 typedef typename super_type::const_reference const_reference; 48 typedef typename super_type::const_iterator const_iterator; 49 typedef typename super_type::const_reverse_iterator const_reverse_iterator; 50 typedef typename super_type::element element; 51 typedef typename super_type::size_type size_type; 52 typedef typename super_type::difference_type difference_type; 53 typedef typename super_type::index index; 54 typedef typename super_type::extent_range extent_range; 55 56 // template typedefs 57 template <std::size_t NDims> 58 struct const_array_view { 59 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; 60 }; 61 62 template <std::size_t NDims> 63 struct array_view { 64 typedef boost::detail::multi_array::multi_array_view<T,NDims> type; 65 }; 66 67 template <typename OPtr> const_multi_array_view(const const_multi_array_view<T,NumDims,OPtr> & other)68 const_multi_array_view(const 69 const_multi_array_view<T,NumDims,OPtr>& other) : 70 base_(other.base_), origin_offset_(other.origin_offset_), 71 num_elements_(other.num_elements_), extent_list_(other.extent_list_), 72 stride_list_(other.stride_list_), index_base_list_(other.index_base_list_) 73 { } 74 75 76 template <class BaseList> 77 #ifdef BOOST_NO_SFINAE 78 void 79 #else 80 typename 81 disable_if<typename boost::is_integral<BaseList>::type,void >::type 82 #endif reindex(const BaseList & values)83 reindex(const BaseList& values) { 84 boost::function_requires< 85 CollectionConcept<BaseList> >(); 86 boost::detail::multi_array:: 87 copy_n(values.begin(),num_dimensions(),index_base_list_.begin()); 88 origin_offset_ = 89 this->calculate_indexing_offset(stride_list_,index_base_list_); 90 } 91 reindex(index value)92 void reindex(index value) { 93 index_base_list_.assign(value); 94 origin_offset_ = 95 this->calculate_indexing_offset(stride_list_,index_base_list_); 96 } 97 num_dimensions() const98 size_type num_dimensions() const { return NumDims; } 99 size() const100 size_type size() const { return extent_list_.front(); } max_size() const101 size_type max_size() const { return num_elements(); } empty() const102 bool empty() const { return size() == 0; } 103 shape() const104 const size_type* shape() const { 105 return extent_list_.data(); 106 } 107 strides() const108 const index* strides() const { 109 return stride_list_.data(); 110 } 111 origin() const112 const T* origin() const { return base_+origin_offset_; } 113 num_elements() const114 size_type num_elements() const { return num_elements_; } 115 index_bases() const116 const index* index_bases() const { 117 return index_base_list_.data(); 118 } 119 120 template <typename IndexList> operator ()(IndexList indices) const121 const element& operator()(IndexList indices) const { 122 boost::function_requires< 123 CollectionConcept<IndexList> >(); 124 return super_type::access_element(boost::type<const element&>(), 125 indices,origin(), 126 shape(),strides(),index_bases()); 127 } 128 129 // Only allow const element access operator [](index idx) const130 const_reference operator[](index idx) const { 131 return super_type::access(boost::type<const_reference>(), 132 idx,origin(), 133 shape(),strides(), 134 index_bases()); 135 } 136 137 // see generate_array_view in base.hpp 138 template <int NDims> 139 typename const_array_view<NDims>::type operator [](const boost::detail::multi_array::index_gen<NumDims,NDims> & indices) const140 operator[](const boost::detail::multi_array:: 141 index_gen<NumDims,NDims>& indices) 142 const { 143 typedef typename const_array_view<NDims>::type return_type; 144 return 145 super_type::generate_array_view(boost::type<return_type>(), 146 indices, 147 shape(), 148 strides(), 149 index_bases(), 150 origin()); 151 } begin() const152 const_iterator begin() const { 153 return const_iterator(*index_bases(),origin(), 154 shape(),strides(),index_bases()); 155 } 156 end() const157 const_iterator end() const { 158 return const_iterator(*index_bases()+(index)*shape(),origin(), 159 shape(),strides(),index_bases()); 160 } 161 rbegin() const162 const_reverse_iterator rbegin() const { 163 return const_reverse_iterator(end()); 164 } 165 rend() const166 const_reverse_iterator rend() const { 167 return const_reverse_iterator(begin()); 168 } 169 170 171 template <typename OPtr> operator ==(const const_multi_array_view<T,NumDims,OPtr> & rhs) const172 bool operator==(const 173 const_multi_array_view<T,NumDims,OPtr>& rhs) 174 const { 175 if(std::equal(extent_list_.begin(), 176 extent_list_.end(), 177 rhs.extent_list_.begin())) 178 return std::equal(begin(),end(),rhs.begin()); 179 else return false; 180 } 181 182 template <typename OPtr> operator <(const const_multi_array_view<T,NumDims,OPtr> & rhs) const183 bool operator<(const 184 const_multi_array_view<T,NumDims,OPtr>& rhs) 185 const { 186 return std::lexicographical_compare(begin(),end(),rhs.begin(),rhs.end()); 187 } 188 189 template <typename OPtr> operator !=(const const_multi_array_view<T,NumDims,OPtr> & rhs) const190 bool operator!=(const 191 const_multi_array_view<T,NumDims,OPtr>& rhs) 192 const { 193 return !(*this == rhs); 194 } 195 196 template <typename OPtr> operator >(const const_multi_array_view<T,NumDims,OPtr> & rhs) const197 bool operator>(const 198 const_multi_array_view<T,NumDims,OPtr>& rhs) 199 const { 200 return rhs < *this; 201 } 202 203 template <typename OPtr> operator <=(const const_multi_array_view<T,NumDims,OPtr> & rhs) const204 bool operator<=(const 205 const_multi_array_view<T,NumDims,OPtr>& rhs) 206 const { 207 return !(*this > rhs); 208 } 209 210 template <typename OPtr> operator >=(const const_multi_array_view<T,NumDims,OPtr> & rhs) const211 bool operator>=(const 212 const_multi_array_view<T,NumDims,OPtr>& rhs) 213 const { 214 return !(*this < rhs); 215 } 216 217 218 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 219 protected: 220 template <typename,std::size_t> friend class multi_array_impl_base; 221 template <typename,std::size_t,typename> friend class const_multi_array_view; 222 #else 223 public: // should be protected 224 #endif 225 226 // This constructor is used by multi_array_impl_base::generate_array_view 227 // to create strides 228 template <typename ExtentList, typename Index> const_multi_array_view(TPtr base,const ExtentList & extents,const boost::array<Index,NumDims> & strides)229 explicit const_multi_array_view(TPtr base, 230 const ExtentList& extents, 231 const boost::array<Index,NumDims>& strides): 232 base_(base), origin_offset_(0) { 233 234 index_base_list_.assign(0); 235 236 // Get the extents and strides 237 boost::detail::multi_array:: 238 copy_n(extents.begin(),NumDims,extent_list_.begin()); 239 boost::detail::multi_array:: 240 copy_n(strides.begin(),NumDims,stride_list_.begin()); 241 242 // Calculate the array size 243 num_elements_ = std::accumulate(extent_list_.begin(),extent_list_.end(), 244 size_type(1),std::multiplies<size_type>()); 245 } 246 247 typedef boost::array<size_type,NumDims> size_list; 248 typedef boost::array<index,NumDims> index_list; 249 250 TPtr base_; 251 index origin_offset_; 252 size_type num_elements_; 253 size_list extent_list_; 254 index_list stride_list_; 255 index_list index_base_list_; 256 257 private: 258 // const_multi_array_view cannot be assigned to (no deep copies!) 259 const_multi_array_view& operator=(const const_multi_array_view& other); 260 }; 261 262 263 template <typename T, std::size_t NumDims> 264 class multi_array_view : 265 public const_multi_array_view<T,NumDims,T*> 266 { 267 typedef const_multi_array_view<T,NumDims,T*> super_type; 268 public: 269 typedef typename super_type::value_type value_type; 270 typedef typename super_type::reference reference; 271 typedef typename super_type::iterator iterator; 272 typedef typename super_type::reverse_iterator reverse_iterator; 273 typedef typename super_type::const_reference const_reference; 274 typedef typename super_type::const_iterator const_iterator; 275 typedef typename super_type::const_reverse_iterator const_reverse_iterator; 276 typedef typename super_type::element element; 277 typedef typename super_type::size_type size_type; 278 typedef typename super_type::difference_type difference_type; 279 typedef typename super_type::index index; 280 typedef typename super_type::extent_range extent_range; 281 282 // template typedefs 283 template <std::size_t NDims> 284 struct const_array_view { 285 typedef boost::detail::multi_array::const_multi_array_view<T,NDims> type; 286 }; 287 288 template <std::size_t NDims> 289 struct array_view { 290 typedef boost::detail::multi_array::multi_array_view<T,NDims> type; 291 }; 292 293 // Assignment from other ConstMultiArray types. 294 template <typename ConstMultiArray> operator =(const ConstMultiArray & other)295 multi_array_view& operator=(const ConstMultiArray& other) { 296 function_requires< 297 boost::multi_array_concepts:: 298 ConstMultiArrayConcept<ConstMultiArray,NumDims> >(); 299 300 // make sure the dimensions agree 301 BOOST_ASSERT(other.num_dimensions() == this->num_dimensions()); 302 BOOST_ASSERT(std::equal(other.shape(),other.shape()+this->num_dimensions(), 303 this->shape())); 304 // iterator-based copy 305 std::copy(other.begin(),other.end(),begin()); 306 return *this; 307 } 308 309 operator =(const multi_array_view & other)310 multi_array_view& operator=(const multi_array_view& other) { 311 if (&other != this) { 312 // make sure the dimensions agree 313 BOOST_ASSERT(other.num_dimensions() == this->num_dimensions()); 314 BOOST_ASSERT(std::equal(other.shape(), 315 other.shape()+this->num_dimensions(), 316 this->shape())); 317 // iterator-based copy 318 std::copy(other.begin(),other.end(),begin()); 319 } 320 return *this; 321 } 322 origin()323 element* origin() { return this->base_+this->origin_offset_; } 324 325 template <class IndexList> operator ()(const IndexList & indices)326 element& operator()(const IndexList& indices) { 327 boost::function_requires< 328 CollectionConcept<IndexList> >(); 329 return super_type::access_element(boost::type<element&>(), 330 indices,origin(), 331 this->shape(),this->strides(), 332 this->index_bases()); 333 } 334 335 operator [](index idx)336 reference operator[](index idx) { 337 return super_type::access(boost::type<reference>(), 338 idx,origin(), 339 this->shape(),this->strides(), 340 this->index_bases()); 341 } 342 343 344 // see generate_array_view in base.hpp 345 template <int NDims> 346 typename array_view<NDims>::type operator [](const boost::detail::multi_array::index_gen<NumDims,NDims> & indices)347 operator[](const boost::detail::multi_array:: 348 index_gen<NumDims,NDims>& indices) { 349 typedef typename array_view<NDims>::type return_type; 350 return 351 super_type::generate_array_view(boost::type<return_type>(), 352 indices, 353 this->shape(), 354 this->strides(), 355 this->index_bases(), 356 origin()); 357 } 358 359 begin()360 iterator begin() { 361 return iterator(*this->index_bases(),origin(), 362 this->shape(),this->strides(), 363 this->index_bases()); 364 } 365 end()366 iterator end() { 367 return iterator(*this->index_bases()+(index)*this->shape(),origin(), 368 this->shape(),this->strides(), 369 this->index_bases()); 370 } 371 rbegin()372 reverse_iterator rbegin() { 373 return reverse_iterator(end()); 374 } 375 rend()376 reverse_iterator rend() { 377 return reverse_iterator(begin()); 378 } 379 380 // Using declarations don't seem to work for g++ 381 // These are the proxies to work around this. 382 origin() const383 const element* origin() const { return super_type::origin(); } 384 385 template <class IndexList> operator ()(const IndexList & indices) const386 const element& operator()(const IndexList& indices) const { 387 boost::function_requires< 388 CollectionConcept<IndexList> >(); 389 return super_type::operator()(indices); 390 } 391 operator [](index idx) const392 const_reference operator[](index idx) const { 393 return super_type::operator[](idx); 394 } 395 396 // see generate_array_view in base.hpp 397 template <int NDims> 398 typename const_array_view<NDims>::type operator [](const boost::detail::multi_array::index_gen<NumDims,NDims> & indices) const399 operator[](const boost::detail::multi_array:: 400 index_gen<NumDims,NDims>& indices) 401 const { 402 return super_type::operator[](indices); 403 } 404 begin() const405 const_iterator begin() const { 406 return super_type::begin(); 407 } 408 end() const409 const_iterator end() const { 410 return super_type::end(); 411 } 412 rbegin() const413 const_reverse_iterator rbegin() const { 414 return super_type::rbegin(); 415 } 416 rend() const417 const_reverse_iterator rend() const { 418 return super_type::rend(); 419 } 420 421 #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 422 private: 423 template <typename,std::size_t> friend class multi_array_impl_base; 424 #else 425 public: // should be private 426 #endif 427 428 // constructor used by multi_array_impl_base::generate_array_view to 429 // generate array views 430 template <typename ExtentList, typename Index> multi_array_view(T * base,const ExtentList & extents,const boost::array<Index,NumDims> & strides)431 explicit multi_array_view(T* base, 432 const ExtentList& extents, 433 const boost::array<Index,NumDims>& strides) : 434 super_type(base,extents,strides) { } 435 436 }; 437 438 } // namespace multi_array 439 } // namespace detail 440 441 // 442 // traits classes to get array_view types 443 // 444 template <typename Array, int N> 445 class array_view_gen { 446 typedef typename Array::element element; 447 public: 448 typedef boost::detail::multi_array::multi_array_view<element,N> type; 449 }; 450 451 template <typename Array, int N> 452 class const_array_view_gen { 453 typedef typename Array::element element; 454 public: 455 typedef boost::detail::multi_array::const_multi_array_view<element,N> type; 456 }; 457 458 } // namespace boost 459 460 #endif 461