1 /* 2 * tensorview.h 3 * 4 * Created on: Dec 28, 2013 5 * Author: evaleev 6 */ 7 8 #ifndef BTAS_TENSORVIEW_H_ 9 #define BTAS_TENSORVIEW_H_ 10 11 #include <functional> 12 13 #include <btas/storage_traits.h> 14 #include <btas/util/sequence_adaptor.h> 15 #include <btas/tensorview_iterator.h> 16 #include <btas/defaults.h> 17 #include <btas/util/functional.h> 18 #include <btas/error.h> 19 20 namespace btas { 21 22 enum TensorViewPolicy_ConstnessPolicy { 23 TensorViewPolicy_RuntimeConst = 1, 24 TensorViewPolicy_CompiletimeConst = 0 25 }; 26 27 /// TensorViewPolicy configures behavior of certain features of TensorView 28 /// \tparam RuntimeConst: if true, constness of data access is checked at runtime. This involves 29 /// extra space overhead (enough to store a boolean readwrite flag). Non-const data access members 30 /// will also check whether readwrite is set using assert (hence runtime overhead can be eliminated after 31 /// testing. This feature is needed if you want to use a single TensorView<T,Range,Storage> type 32 /// for mutable (non-const) and immutable (const) views. The default value is false, which requires use 33 /// of TensorView<T,Range,const Storage>, aka TensorConstView<T.Range,Storage>, for immutable views. 34 template <TensorViewPolicy_ConstnessPolicy ConstnessPolicy = TensorViewPolicy_CompiletimeConst> 35 struct TensorViewPolicy { 36 /// true if constness tracked at runtime 37 static constexpr bool runtimeconst = (ConstnessPolicy == TensorViewPolicy_RuntimeConst); 38 }; 39 40 /// View (aka generalized slice) of a tensor 41 42 /** 43 @tparam _T apparent element type, TensorView will present tensor elements as values of this type 44 @tparam _Range Range type 45 @tparam _Storage Storage type 46 */ 47 template<typename _T, 48 class _Range = btas::DEFAULT::range, 49 class _Storage = btas::DEFAULT::storage<_T>, 50 class _Policy = btas::TensorViewPolicy<> 51 > 52 class TensorView { 53 54 public: 55 56 /// value type 57 typedef _T value_type; 58 59 /// type of Range 60 typedef _Range range_type; 61 62 /// type of index 63 typedef typename _Range::index_type index_type; 64 65 /// type of underlying data storage 66 typedef _Storage storage_type; 67 68 /// type of data storage reference 69 typedef std::reference_wrapper<storage_type> storageref_type; 70 71 /// size type 72 typedef typename storage_traits<storage_type>::size_type size_type; 73 74 /// element iterator 75 typedef TensorViewIterator<range_type, storage_type> iterator; 76 77 /// element iterator 78 typedef TensorViewIterator<range_type, const storage_type> const_iterator; 79 80 private: 81 struct Enabler {}; 82 83 public: 84 85 /// destructor ~TensorView()86 ~TensorView () { } 87 88 /// move-construct from \c range and \c storageref ; write access must be passed explicitly if \c _Policy requires 89 template<class Policy = _Policy, class = typename std::enable_if<not Policy::runtimeconst>::type> 90 explicit 91 TensorView (range_type&& range, 92 storageref_type&& storageref, 93 bool can_write = not _Policy::runtimeconst ? not std::is_const<storage_type>::value : false) : range_(range)94 range_(range), storageref_(storageref), can_write_(can_write) 95 { 96 } 97 98 /// conversion from const Tensor into TensorConstView 99 template<class _Tensor, 100 class Storage = _Storage, 101 class = typename std::enable_if<is_boxtensor<_Tensor>::value && 102 std::is_const<Storage>::value>::type 103 > TensorView(const _Tensor & x)104 TensorView (const _Tensor& x) 105 : range_ (x.range()), 106 storageref_(std::cref(x.storage())), 107 can_write_(false) 108 { 109 } 110 111 /// conversion from const Tensor to non-const View only possible if \c Policy::runtimeconst is \c true 112 template<class _Tensor, 113 class Storage = _Storage, 114 class Policy = _Policy, 115 class = typename std::enable_if<is_boxtensor<_Tensor>::value && 116 not std::is_const<Storage>::value && 117 Policy::runtimeconst>::type 118 > TensorView(const _Tensor & x)119 TensorView (const _Tensor& x) 120 : range_ (x.range()), 121 storageref_(std::ref(const_cast<storage_type&>(x.storage()))), 122 can_write_(false) 123 { 124 } 125 126 /// conversion from non-const Tensor 127 template<class _Tensor, 128 class Storage = _Storage, 129 class = typename std::enable_if<is_boxtensor<_Tensor>::value && 130 std::is_same<typename _Tensor::storage_type,Storage>::value>::type> TensorView(_Tensor & x)131 TensorView (_Tensor& x) 132 : range_ (x.range()), 133 storageref_(std::ref(x.storage())), 134 can_write_(true) 135 { 136 } 137 138 /// conversion from non-const TensorView 139 template<class __T, 140 class __Range, 141 class __Storage, 142 class __Policy, 143 class = typename std::enable_if<not std::is_const<__Storage>::value>::type> TensorView(TensorView<__T,__Range,__Storage,__Policy> & x)144 TensorView (TensorView<__T,__Range,__Storage,__Policy>& x) 145 : range_ (x.range()), 146 storageref_(std::ref(x.storage())), 147 can_write_(_Policy::runtimeconst ? bool(x.can_write_) : not std::is_const<storage_type>::value) 148 { 149 } 150 151 /// standard copy constructor TensorView(const TensorView & x)152 TensorView (const TensorView& x) : 153 range_ (x.range_), 154 storageref_(x.storageref_), 155 can_write_(false) 156 { 157 } 158 159 /// copy assignment 160 TensorView& 161 operator= (const TensorView& x) 162 { 163 range_ = x.range_; 164 storageref_ = x.storageref_; 165 can_write_ = x.can_write_; 166 return *this; 167 } 168 169 /// move constructor TensorView(TensorView && x)170 TensorView (TensorView&& x) : range_(), storageref_(x.storageref_), can_write_(x.can_write_) 171 { 172 std::swap(range_, x.range_); 173 } 174 175 /// move assignment operator 176 TensorView& 177 operator= (TensorView&& x) 178 { 179 std::swap(range_, x.range_); 180 std::swap(storageref_, x.storageref_); 181 std::swap(can_write_, x.can_write_); 182 return *this; 183 } 184 185 /// number of indices (tensor rank) 186 size_type rank()187 rank () const 188 { 189 return range_.rank(); 190 } 191 192 /// \return number of elements 193 size_type size()194 size () const 195 { 196 return range_.area(); 197 } 198 199 /// \return range object 200 const range_type& range()201 range() const 202 { 203 return range_; 204 } 205 206 /// \param d dimension 207 /// \return subrange for dimension \d 208 const Range1d<typename index_type::value_type> range(size_t d)209 range(size_t d) const 210 { 211 return range_.range(d); 212 } 213 214 /// \return range's extent object 215 typename range_type::extent_type extent()216 extent() const 217 { 218 return range_.extent(); 219 } 220 221 /// \return extent of range along dimension \c d 222 typename range_type::extent_type::value_type extent(size_t d)223 extent(size_t d) const 224 { 225 return range_.extent(d); 226 } 227 228 /// \return storage object 229 const storage_type& storage()230 storage() const 231 { 232 return storageref_.get(); 233 } 234 235 /// \return storage object 236 storage_type& storage()237 storage() 238 { 239 assert_writable(); 240 return storageref_.get(); 241 } 242 243 /// test whether TensorView is empty 244 bool empty()245 empty() const 246 { 247 return range_.area() == 0; 248 } 249 250 /// \return const iterator begin 251 const_iterator begin()252 begin() const 253 { 254 return cbegin(); 255 } 256 257 /// \return begin iterator 258 iterator begin()259 begin() 260 { 261 assert_writable(); 262 return iterator(range().begin(), storage()); 263 } 264 265 /// \return const end iterator 266 const_iterator end()267 end() const 268 { 269 return cend(); 270 } 271 272 /// \return const end iterator 273 iterator end()274 end() 275 { 276 assert_writable(); 277 return iterator(range().end(), storageref_); 278 } 279 280 /// \return const iterator begin, even if this is not itself const 281 const_iterator cbegin()282 cbegin() const 283 { 284 return const_iterator(range().begin(), storage()); 285 } 286 287 /// \return const iterator end, even if this is not itself const 288 const_iterator cend()289 cend() const 290 { 291 return const_iterator(range().end(), storage()); 292 } 293 294 /// Immutable access to an element without range check. 295 296 /// Available when \c value_type == \c storage_type::value_type 297 /// \return const reference to the element indexed by {\c first, \c rest} 298 template<typename index0, typename... _args> 299 typename std::enable_if<std::is_integral<index0>::value && 300 std::is_same<value_type,typename storage_type::value_type>::value, 301 const value_type& 302 >::type operator()303 operator() (const index0& first, const _args&... rest) const 304 { 305 typedef typename common_signed_type<index0, typename index_type::value_type>::type ctype; 306 auto indexv = {static_cast<ctype>(first), static_cast<ctype>(rest)...}; 307 index_type index = array_adaptor<index_type>::construct(indexv.size()); 308 std::copy(std::begin(indexv), std::end(indexv), std::begin(index)); 309 return storageref_.get()[ range_.ordinal(index) ]; 310 } 311 312 /// Immutable access to an element without range check. 313 314 /// Available when \c value_type == \c storage_type::value_type 315 /// \return const reference to the element indexed by \c index 316 template <typename Index> 317 typename std::enable_if<is_index<Index>::value && 318 std::is_same<value_type,typename storage_type::value_type>::value, 319 const value_type& 320 >::type operator()321 operator() (const Index& index) const 322 { 323 return storageref_.get()[range_.ordinal(index)]; 324 } 325 326 /// Mutable access to an element without range check. 327 328 /// Available when \c value_type == \c storage_type::value_type 329 /// \return reference to the element indexed by {\c first, \c rest} 330 template<typename index0, typename... _args> 331 typename std::enable_if<std::is_integral<index0>::value && 332 std::is_same<value_type,typename storage_type::value_type>::value && 333 not std::is_const<storage_type>::value, 334 value_type& 335 >::type operator()336 operator() (const index0& first, const _args&... rest) 337 { 338 assert_writable(); 339 typedef typename common_signed_type<index0, typename index_type::value_type>::type ctype; 340 auto indexv = {static_cast<ctype>(first), static_cast<ctype>(rest)...}; 341 index_type index = array_adaptor<index_type>::construct(indexv.size()); 342 std::copy(std::begin(indexv), std::end(indexv), std::begin(index)); 343 return storageref_.get()[ range_.ordinal(index) ]; 344 } 345 346 /// Mutable access to an element without range check (rank() == general) 347 348 /// Available when \c value_type == \c storag_type::value_type 349 /// \return reference to the element indexed by \c index 350 template <typename Index> 351 typename std::enable_if<is_index<Index>::value && 352 std::is_same<value_type,typename storage_type::value_type>::value && 353 not std::is_const<storage_type>::value, 354 value_type& 355 >::type operator()356 operator() (const Index& index) 357 { 358 assert_writable(); 359 return storageref_.get()[range_.ordinal(index)]; 360 } 361 362 /// Immutable access to an element without range check. 363 364 /// Available when \c value_type != \c storage_type::value_type 365 /// \return value of the element indexed by {\c first, \c rest} 366 template<typename index0, typename... _args> 367 typename std::enable_if<std::is_integral<index0>::value && 368 not std::is_same<value_type,typename storage_type::value_type>::value, 369 value_type>::type operator()370 operator() (const index0& first, const _args&... rest) const 371 { 372 typedef typename common_signed_type<index0, typename index_type::value_type>::type ctype; 373 auto indexv = {static_cast<ctype>(first), static_cast<ctype>(rest)...}; 374 index_type index = array_adaptor<index_type>::construct(indexv.size()); 375 std::copy(std::begin(indexv), std::end(indexv), std::begin(index)); 376 return storageref_.get()[ range_.ordinal(index) ]; 377 } 378 379 /// Immutable access to an element without range check (rank() == general) 380 381 /// Available when \c value_type != \c storage_type::value_type 382 /// \return value of the element indexed by \c index 383 template <typename Index> 384 typename std::enable_if<is_index<Index>::value && 385 not std::is_same<value_type,typename storage_type::value_type>::value, 386 value_type 387 >::type operator()388 operator() (const Index& index) const 389 { 390 return storageref_.get()[range_.ordinal(index)]; 391 } 392 393 394 /// \return element without range check 395 template<typename index0, typename... _args> 396 typename std::enable_if<std::is_integral<index0>::value && 397 std::is_same<value_type,typename storage_type::value_type>::value, 398 const value_type&>::type at(const index0 & first,const _args &...rest)399 at (const index0& first, const _args&... rest) const 400 { 401 typedef typename common_signed_type<index0, typename index_type::value_type>::type ctype; 402 auto indexv = {static_cast<ctype>(first), static_cast<ctype>(rest)...}; 403 index_type index = array_adaptor<index_type>::construct(indexv.size()); 404 std::copy(std::begin(indexv), std::end(indexv), std::begin(index)); 405 assert( range_.includes(index) ); 406 return storageref_.get()[ range_.ordinal(index) ]; 407 } 408 409 /// \return element without range check (rank() == general) 410 template <typename Index> 411 typename std::enable_if<is_index<Index>::value && 412 std::is_same<value_type,typename storage_type::value_type>::value, 413 const value_type&>::type at(const Index & index)414 at (const Index& index) const 415 { 416 assert( range_.includes(index) ); 417 return storageref_.get()[ range_.ordinal(index) ]; 418 } 419 420 /// access element without range check 421 template<typename index0, typename... _args> 422 typename std::enable_if<std::is_integral<index0>::value && 423 std::is_same<value_type,typename storage_type::value_type>::value && 424 not std::is_const<storage_type>::value, 425 value_type&>::type at(const index0 & first,const _args &...rest)426 at (const index0& first, const _args&... rest) 427 { 428 assert_writable(); 429 typedef typename common_signed_type<index0, typename index_type::value_type>::type ctype; 430 auto indexv = {static_cast<ctype>(first), static_cast<ctype>(rest)...}; 431 index_type index = array_adaptor<index_type>::construct(indexv.size()); 432 std::copy(std::begin(indexv), std::end(indexv), std::begin(index)); 433 assert( range_.includes(index) ); 434 return storageref_.get()[ range_.ordinal(index) ]; 435 } 436 437 /// access element without range check (rank() == general) 438 template <typename Index> 439 typename std::enable_if<is_index<Index>::value && 440 std::is_same<value_type,typename storage_type::value_type>::value && 441 not std::is_const<storage_type>::value, 442 value_type&>::type at(const Index & index)443 at (const Index& index) 444 { 445 assert_writable(); 446 assert( range_.includes(index) ); 447 return storageref_.get()[ range_.ordinal(index) ]; 448 } 449 450 /// swap this and x 451 void swap(TensorView & x)452 swap (TensorView& x) 453 { 454 std::swap(range_, x.range_); 455 std::swap(storageref_, x.storageref_); 456 std::swap(can_write_, x.can_write_); 457 } 458 459 // ========== Finished Public Interface and Its Reference Implementations ========== 460 461 // 462 // Here come Non-Standard members (to be discussed) 463 // 464 #if 0 465 /// addition assignment 466 TensorView& 467 operator+= (const TensorView& x) 468 { 469 assert( std::equal(range_.begin(), range_.end(), x.range_.begin()) ); 470 std::transform(storageref_.begin(), storageref_.end(), x.storageref_.begin(), storageref_.begin(), std::plus<value_type>()); 471 return *this; 472 } 473 474 /// addition of tensors 475 TensorView 476 operator+ (const TensorView& x) const 477 { 478 TensorView y(*this); y += x; 479 return y; /* automatically called move semantics */ 480 } 481 482 /// subtraction assignment 483 TensorView& 484 operator-= (const TensorView& x) 485 { 486 assert( 487 std::equal(range_.begin(), range_.end(), x.range_.begin())); 488 std::transform(storageref_.begin(), storageref_.end(), x.storageref_.begin(), storageref_.begin(), std::minus<value_type>()); 489 return *this; 490 } 491 492 /// subtraction of tensors 493 TensorView 494 operator- (const TensorView& x) const 495 { 496 TensorView y(*this); y -= x; 497 return y; /* automatically called move semantics */ 498 } 499 500 /// fill all elements by val 501 void 502 fill (const value_type& val) 503 { 504 std::fill(storageref_.begin(), storageref_.end(), val); 505 } 506 507 /// generate all elements by gen() 508 template<class Generator> 509 void 510 generate (Generator gen) 511 { 512 std::generate(storageref_.begin(), storageref_.end(), gen); 513 } 514 #endif 515 writable()516 bool writable() const { 517 return can_write_; 518 } 519 520 private: 521 522 range_type range_;///< range object 523 storageref_type storageref_;///< dataref 524 typedef typename std::conditional<_Policy::runtimeconst, 525 bool, 526 btas::detail::bool_type<not std::is_const<storage_type>::value> 527 >::type writable_type; 528 writable_type can_write_; 529 530 /// use this in non-const members to assert writability if Policy calls for runtime const check assert_writable()531 void assert_writable() const { 532 if (_Policy::runtimeconst) 533 BTAS_ASSERT(can_write_); 534 } 535 536 /// construct from \c range and \c storage; pass \c can_write explicitly if needed 537 explicit TensorView (range_type&& range, storage_type& storage, 538 bool can_write = not _Policy::runtimeconst ? not std::is_const<storage_type>::value : false) : range_(std::move (range))539 range_(std::move(range)), storageref_(std::ref(storage)), can_write_(can_write) { 540 } 541 542 template <typename T, 543 typename Range, 544 typename Storage, 545 typename Policy> 546 friend TensorView<T, 547 Range, 548 typename std::conditional<std::is_same<T,typename Storage::value_type>::value, 549 Storage, 550 typename std::add_const<Storage>::type 551 >::type, 552 Policy> 553 __make_view(Range&& range, Storage& storage, 554 Policy, 555 bool can_write); 556 template <typename T, 557 typename Range, 558 typename Storage, 559 typename Policy> 560 friend TensorView<T, Range, const Storage, Policy> __make_cview(Range&& range, const Storage& storage, Policy); 561 562 template <class __T, 563 class __Range, 564 class __Storage, 565 class __Policy> 566 friend class TensorView; 567 }; // end of TensorView 568 569 /// TensorConstView is a read-only variant of TensorView 570 template <typename _T, 571 class _Range = btas::DEFAULT::range, 572 class _Storage = btas::DEFAULT::storage<_T>, 573 class _Policy = btas::TensorViewPolicy<> 574 > 575 using TensorConstView = TensorView<_T, _Range, const _Storage, _Policy>; 576 577 /// TensorRWView is a variant of TensorView with runtime write access check 578 template <typename _T, 579 class _Range = btas::DEFAULT::range, 580 class _Storage = btas::DEFAULT::storage<_T>, 581 class _Policy = btas::TensorViewPolicy<TensorViewPolicy_RuntimeConst> 582 > 583 using TensorRWView = TensorView<_T, _Range, typename std::remove_const<_Storage>::type, _Policy>; 584 585 586 /// Helper function (friendly to TensorView) that constructs a view with an explicitly-specified element type of the view. Useful if need to 587 /// view a tensor of floats as a tensor of complex floats. 588 /// \tparam T the element type of the resulting view 589 /// \tparam Range the range type 590 /// \tparam Storage the storage type 591 /// \tparam Policy the TensorViewPolicy type 592 /// \param range the range object defining the view 593 /// \param storage the storage object that will be viewed into 594 /// \return TensorView into \c storage using \c range and policy \c Policy 595 /// \attention use __make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 596 template <typename T, 597 typename Range, 598 typename Storage, 599 typename Policy> 600 TensorView<T, 601 Range, 602 typename std::conditional<std::is_same<T,typename Storage::value_type>::value, 603 Storage, 604 typename std::add_const<Storage>::type 605 >::type, 606 Policy> 607 __make_view(Range&& range, Storage& storage, 608 Policy = Policy(), 609 bool can_write = not Policy::runtimeconst 610 ? (not std::is_const<Storage>::value && std::is_same<T,typename Storage::value_type>::value) 611 : false) 612 { 613 typedef TensorView<T, 614 Range, 615 typename std::conditional<std::is_same<T,typename Storage::value_type>::value, 616 Storage, 617 typename std::add_const<Storage>::type 618 >::type, 619 Policy> result_type; 620 return result_type(std::move(range), storage, can_write); 621 } 622 623 /// Helper function (friendly to TensorView) that constructs a view, with an explicitly-specified element type of the view. Useful if need to 624 /// view a tensor of floats as a tensor of complex floats. \sa TensorConstView 625 /// \tparam T the element type of the resulting view 626 /// \tparam Range the range type 627 /// \tparam Storage the storage type 628 /// \param range the range object defining the view 629 /// \param storage the storage object that will be viewed into 630 /// \return TensorView into \c storage using \c range and policy \c Policy 631 template <typename T, 632 typename Range, 633 typename Storage, 634 typename Policy> 635 TensorView<T, Range, const Storage, Policy> 636 __make_cview(Range&& range, const Storage& storage, Policy = Policy()) 637 { 638 return TensorView<T, Range, const Storage, Policy>(std::move(range), storage, false); 639 } 640 641 /// Helper function that constructs TensorView. 642 /// \tparam Range the range type 643 /// \tparam Storage the storage type 644 /// \tparam Policy the TensorViewPolicy type; if the Policy requires additional runtime parameters use __make_view instead 645 /// \param range the range object defining the view 646 /// \param storage the storage object that will be viewed into 647 /// \return TensorView into \c storage using \c range, with policy \c Policy 648 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 649 template <typename Range, 650 typename Storage, 651 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 652 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 653 TensorView<typename Storage::value_type, Range, Storage, Policy> 654 make_view(const Range& range, Storage& storage, Policy = Policy()) 655 { 656 return make_view<typename Storage::value_type, Range, Storage, Policy>(range, storage); 657 } 658 659 /// Helper function that constructs TensorView. 660 /// \tparam Range the range type 661 /// \tparam Storage the storage type 662 /// \tparam Policy the TensorViewPolicy type 663 /// \param range the range object defining the view 664 /// \param storage the storage object that will be viewed into 665 /// \return TensorView into \c storage using \c range, with policy \c Policy 666 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 667 template <typename Range, 668 typename Storage, 669 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 670 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 671 TensorView<typename Storage::value_type, Range, Storage, Policy> 672 make_view(Range&& range, Storage& storage, Policy = Policy()) 673 { 674 return make_view<typename Storage::value_type, Range, Storage, Policy>(range, storage); 675 } 676 677 678 /// Helper function that constructs TensorView, with an explicitly-specified element type of the view. Useful if need to 679 /// view a tensor of floats as a tensor of complex floats. 680 /// \tparam T the element type of the resulting view 681 /// \tparam Range the range type 682 /// \tparam Storage the storage type 683 /// \tparam Policy the TensorViewPolicy type 684 /// \param range the range object defining the view 685 /// \param storage the storage object that will be viewed into 686 /// \return TensorView into \c storage using \c range, with policy \c Policy 687 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 688 template <typename T, 689 typename Range, 690 typename Storage, 691 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 692 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 693 auto 694 make_view(const Range& range, Storage& storage, Policy = Policy()) -> decltype(__make_view<T, Range, Storage, Policy>(Range(range), storage)) 695 { 696 return __make_view<T, Range, Storage, Policy>(Range(range), storage); 697 } 698 699 /// Helper function that constructs TensorView, with an explicitly-specified element type of the view. Useful if need to 700 /// view a tensor of floats as a tensor of complex floats. 701 /// \tparam T the element type of the resulting view 702 /// \tparam Range the range type 703 /// \tparam Storage the storage type 704 /// \tparam Policy the TensorViewPolicy type 705 /// \param range the range object defining the view 706 /// \param storage the storage object that will be viewed into 707 /// \return TensorView into \c storage using \c range, with policy \c Policy 708 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 709 template <typename T, 710 typename Range, 711 typename Storage, 712 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 713 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 714 auto 715 make_view(Range&& range, Storage& storage, Policy = Policy()) -> decltype(__make_view<T, Range, Storage, Policy>(range, storage)) 716 { 717 return __make_view<T, Range, Storage, Policy>(range, storage); 718 } 719 720 /// Helper function that constructs a full TensorView of a Tensor. 721 /// \tparam Tensor the tensor type 722 /// \param tensor the Tensor object 723 /// \return TensorView, a full view of the \c tensor 724 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c tensor is a const reference. 725 /// \note Provided for completeness. 726 template <typename Tensor, 727 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 728 class = typename std::enable_if<is_boxtensor<Tensor>::value>::type> 729 TensorView<typename Tensor::value_type, 730 typename Tensor::range_type, 731 typename Tensor::storage_type, 732 Policy> 733 make_view(Tensor& tensor, Policy = Policy()) 734 { 735 return TensorView<typename Tensor::value_type, 736 typename Tensor::range_type, 737 typename Tensor::storage_type, 738 Policy>(tensor); 739 } 740 741 /// Helper function that constructs a full TensorView of a Tensor, 742 /// with an explicitly-specified element type of the view. Useful if need to 743 /// view a tensor of floats as a tensor of complex floats. 744 /// \tparam T the element type of the resulting view 745 /// \tparam Tensor the tensor type 746 /// \param tensor the Tensor object 747 /// \return TensorView, a full view of the \c tensor 748 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c tensor is a const reference. 749 /// \note Provided for completeness. 750 template <typename T, typename Tensor, 751 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 752 class = typename std::enable_if<is_boxtensor<Tensor>::value>::type> 753 TensorView<T, 754 typename Tensor::range_type, 755 typename std::conditional<std::is_same<T,typename Tensor::storage_type::value_type>::value, 756 typename Tensor::storage_type, 757 typename std::add_const<typename Tensor::storage_type>::type 758 >::type, 759 Policy> 760 make_view(Tensor& tensor, Policy = Policy()) 761 { 762 typedef TensorView<T, 763 typename Tensor::range_type, 764 typename std::conditional<std::is_same<T,typename Tensor::storage_type::value_type>::value, 765 typename Tensor::storage_type, 766 typename std::add_const<typename Tensor::storage_type>::type 767 >::type, 768 Policy> result_type; 769 return result_type(tensor); 770 } 771 772 /// Helper function that constructs a constant TensorView. \sa TensorConstView 773 /// \tparam Range the range type 774 /// \tparam Storage the storage type 775 /// \param range the range object defining the view 776 /// \param storage the storage object that will be viewed into 777 /// \return TensorView into \c storage using \c range 778 template <typename Range, 779 typename Storage, 780 typename Policy = btas::TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 781 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 782 TensorView<typename Storage::value_type, Range, const Storage, Policy> 783 make_cview(const Range& range, const Storage& storage, Policy = Policy()) 784 { 785 return make_cview<typename Storage::value_type, Range, Storage, Policy>(range, storage); 786 } 787 788 /// Helper function that constructs a constant TensorView, with an explicitly-specified element type of the view. Useful if need to 789 /// view a tensor of floats as a tensor of complex floats. \sa TensorConstView 790 /// \tparam T the element type of the resulting view 791 /// \tparam Range the range type 792 /// \tparam Storage the storage type 793 /// \param range the range object defining the view 794 /// \param storage the storage object that will be viewed into 795 /// \return TensorView into \c storage using \c range 796 template <typename T, 797 typename Range, 798 typename Storage, 799 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 800 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 801 TensorView<T, Range, const Storage, Policy> 802 make_cview(const Range& range, const Storage& storage, Policy = Policy()) 803 { 804 return __make_cview<T, Range, const Storage, Policy>(Range(range), storage); 805 } 806 807 /// Helper function that constructs a full constant TensorView of a Tensor. 808 /// \tparam Tensor the tensor type 809 /// \param tensor the Tensor object 810 /// \return TensorView, a full view of the \c tensor 811 /// \note Provided for completeness. 812 template <typename Tensor, 813 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 814 class = typename std::enable_if<is_boxtensor<Tensor>::value>::type> 815 TensorView<typename Tensor::value_type, 816 typename Tensor::range_type, 817 const typename Tensor::storage_type, 818 Policy> make_cview(const Tensor & tensor)819 make_cview(const Tensor& tensor) 820 { 821 return TensorView<typename Tensor::value_type, 822 typename Tensor::range_type, 823 const typename Tensor::storage_type, 824 Policy>(tensor); 825 } 826 827 /// Helper function that constructs a full constant TensorView of a Tensor, 828 /// with an explicitly-specified element type of the view. Useful if need to 829 /// view a tensor of floats as a tensor of complex floats. 830 /// \tparam T the element type of the resulting view 831 /// \tparam Tensor the tensor type 832 /// \param tensor the Tensor object 833 /// \return TensorView, a full view of the \c tensor 834 /// \note Provided for completeness. 835 template <typename T, typename Tensor, 836 typename Policy = TensorViewPolicy<TensorViewPolicy_CompiletimeConst>, 837 class = typename std::enable_if<is_boxtensor<Tensor>::value>::type> 838 TensorView<T, 839 typename Tensor::range_type, 840 const typename Tensor::storage_type, 841 Policy> make_cview(const Tensor & tensor)842 make_cview(const Tensor& tensor) 843 { 844 return TensorView<T, 845 typename Tensor::range_type, 846 const typename Tensor::storage_type, 847 Policy>(tensor); 848 } 849 850 /// Helper function that constructs writable TensorView. 851 /// \tparam Range the range type 852 /// \tparam Storage the storage type 853 /// \param range the range object defining the view 854 /// \param storage the storage object that will be viewed into 855 /// \return TensorView into \c storage using \c range 856 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 857 template <typename Range, 858 typename Storage, 859 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 860 TensorRWView<typename Storage::value_type, Range, Storage> 861 make_rwview(const Range& range, 862 Storage& storage, 863 bool can_write = not std::is_const<Storage>::value) 864 { 865 // enforce mutability 866 can_write = can_write && (not std::is_const<Storage>::value); 867 return make_rwview(Range(range), storage, can_write); 868 } 869 870 /// Helper function that constructs writable TensorView. 871 /// \tparam Range the range type 872 /// \tparam Storage the storage type 873 /// \param range the range object defining the view 874 /// \param storage the storage object that will be viewed into 875 /// \return TensorView into \c storage using \c range 876 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 877 template <typename Range, 878 typename Storage, 879 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 880 TensorRWView<typename Storage::value_type, Range, Storage> 881 make_rwview(Range&& range, 882 Storage& storage, 883 bool can_write = not std::is_const<Storage>::value) 884 { 885 // enforce mutability 886 can_write = can_write && (not std::is_const<Storage>::value); 887 return make_rwview<typename Storage::value_type, Range, Storage>(std::move(range), storage, can_write); 888 } 889 890 /// Helper function that constructs writable TensorView, with an explicitly-specified element type of the view. Useful if need to 891 /// view a tensor of floats as a tensor of complex floats. 892 /// \tparam T the element type of the resulting view 893 /// \tparam Range the range type 894 /// \tparam Storage the storage type 895 /// \param range the range object defining the view 896 /// \param storage the storage object that will be viewed into 897 /// \return TensorView into \c storage using \c range 898 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 899 template <typename T, 900 typename Range, 901 typename Storage, 902 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 903 TensorRWView<T, Range, Storage> 904 make_rwview(const Range& range, Storage& storage, 905 bool can_write = not std::is_const<Storage>::value && 906 std::is_same<T,typename Storage::value_type>::value) 907 { 908 // enforce mutability 909 can_write = can_write && (not std::is_const<Storage>::value && 910 std::is_same<T,typename Storage::value_type>::value); 911 return make_rwview(Range(range), 912 storage, 913 can_write); 914 } 915 916 /// Helper function that constructs writable TensorView, with an explicitly-specified element type of the view. Useful if need to 917 /// view a tensor of floats as a tensor of complex floats. 918 /// \tparam T the element type of the resulting view 919 /// \tparam Range the range type 920 /// \tparam Storage the storage type 921 /// \param range the range object defining the view 922 /// \param storage the storage object that will be viewed into 923 /// \return TensorView into \c storage using \c range 924 /// \attention use make_cview if you must force a const view; this will provide const view, however, if \c storage is a const reference. 925 template <typename T, 926 typename Range, 927 typename Storage, 928 class = typename std::enable_if<not std::is_reference<Range>::value>::type> 929 TensorRWView<T, Range, Storage> 930 make_rwview(Range&& range, Storage& storage, 931 bool can_write = not std::is_const<Storage>::value && 932 std::is_same<T,typename Storage::value_type>::value) 933 { 934 // enforce mutability 935 can_write = can_write && (not std::is_const<Storage>::value && 936 std::is_same<T,typename Storage::value_type>::value); 937 return __make_view<T, 938 Range, 939 typename std::remove_const<Storage>::type, 940 TensorViewPolicy<TensorViewPolicy_RuntimeConst> >(std::move(range), 941 const_cast<typename std::remove_const<Storage>::type&>(storage), 942 TensorViewPolicy<TensorViewPolicy_RuntimeConst>(), 943 can_write); 944 } 945 946 /// Helper function that constructs a full writable TensorView of a Tensor. 947 /// \tparam Tensor the tensor type 948 /// \param tensor the Tensor object 949 /// \return TensorView, a full view of the \c tensor 950 /// \note Provided for completeness. 951 template <typename Tensor, class = typename std::enable_if<is_boxtensor<Tensor>::value>::type> 952 TensorRWView<typename Tensor::value_type, 953 typename Tensor::range_type, 954 typename Tensor::storage_type> 955 make_rwview(Tensor& tensor, 956 bool can_write = not std::is_const<Tensor>::value && 957 not std::is_const<typename Tensor::storage_type>::value) 958 { 959 // enforce mutability 960 can_write = can_write && (not std::is_const<Tensor>::value && not std::is_const<typename Tensor::storage_type>::value); 961 return make_rwview(tensor.range(), tensor.storage(), can_write); 962 } 963 964 /// Helper function that constructs a full writable TensorView of a Tensor, 965 /// with an explicitly-specified element type of the view. Useful if need to 966 /// view a tensor of floats as a tensor of complex floats. 967 /// \tparam T the element type of the resulting view 968 /// \tparam Tensor the tensor type 969 /// \param tensor the Tensor object 970 /// \return TensorView, a full view of the \c tensor 971 /// \note Provided for completeness. 972 template <typename T, typename Tensor, class = typename std::enable_if<is_boxtensor<Tensor>::value>::type> 973 TensorRWView<T, 974 typename Tensor::range_type, 975 typename Tensor::storage_type> 976 make_rwview(Tensor& tensor, 977 bool can_write = not std::is_const<Tensor>::value && 978 not std::is_const<typename Tensor::storage_type>::value && 979 std::is_same<T,typename Tensor::storage_type::value_type>::value) 980 { 981 // enforce mutability 982 can_write = can_write && 983 (not std::is_const<Tensor>::value && 984 not std::is_const<typename Tensor::storage_type>::value && 985 std::is_same<T,typename Tensor::storage_type::value_type>::value); 986 return make_rwview(tensor.range(), tensor.storage(), can_write); 987 } 988 989 template <typename _T, typename _Range, typename _Storage> 990 auto cbegin(const btas::TensorView<_T, _Range, _Storage>& x) -> decltype(x.cbegin()) { 991 return x.cbegin(); 992 } 993 template <typename _T, typename _Range, typename _Storage> 994 auto cend(const btas::TensorView<_T, _Range, _Storage>& x) -> decltype(x.cbegin()) { 995 return x.cend(); 996 } 997 998 /// maps TensorView -> Range 999 template <typename _T, typename _Range, typename _Storage> 1000 auto 1001 range (const btas::TensorView<_T, _Range, _Storage>& t) -> decltype(t.range()) { 1002 return t.range(); 1003 } 1004 1005 /// maps TensorView -> Range extent 1006 template <typename _T, typename _Range, typename _Storage> 1007 auto 1008 extent (const btas::TensorView<_T, _Range, _Storage>& t) -> decltype(t.range().extent()) { 1009 return t.range().extent(); 1010 } 1011 1012 /// TensorView stream output operator 1013 1014 /// prints TensorView in row-major form. To be implemented elsewhere using slices. 1015 /// \param os The output stream that will be used to print \c t 1016 /// \param t The TensorView to be printed 1017 /// \return A reference to the output stream 1018 template <typename _T, typename _Range, typename _Storage> 1019 std::ostream& operator<<(std::ostream& os, const btas::TensorView<_T, _Range, _Storage>& t) { 1020 os << "TensorView:\n Range: " << t.range() << std::endl; 1021 return os; 1022 } 1023 1024 /// TensorMap views a sequence of values as a Tensor 1025 template <typename _T, 1026 class _Range = btas::DEFAULT::range> 1027 using TensorMap = TensorView<_T, _Range, btas::infinite_sequence_adaptor<_T*>>; 1028 /// TensorConstMap const-views a sequence of values as a Tensor 1029 template <typename _T, 1030 class _Range = btas::DEFAULT::range> 1031 using TensorConstMap = TensorView<const _T, _Range, const btas::infinite_sequence_adaptor<const _T*>>; 1032 1033 /// Helper function that constructs TensorMap. 1034 /// \tparam T the element type returned by the view 1035 /// \tparam Range the range type 1036 /// \param range the range object defining the view 1037 /// \return TensorView into \c storage using \c range 1038 /// \attention use make_cmap if you must force a const view; this will provide const view, however, if \c storage is a const reference. 1039 template <typename T, 1040 typename Range> 1041 TensorMap<T, Range> make_map(T * data,Range && range)1042 make_map(T* data, Range&& range) 1043 { 1044 return TensorMap<T, Range>(std::move(range), 1045 std::ref(btas::infinite_sequence_adaptor<T*>(data))); 1046 } 1047 1048 /// Helper function that constructs TensorConstMap. 1049 /// \tparam T the element type returned by the view 1050 /// \tparam Range the range type 1051 /// \param range the range object defining the view 1052 /// \return TensorView into \c storage using \c range 1053 /// \attention use make_cmap if you must force a const view; this will provide const view, however, if \c storage is a const reference. 1054 template <typename T, 1055 typename Range> 1056 TensorConstMap<T, Range> make_map(const T * data,Range && range)1057 make_map(const T* data, Range&& range) 1058 { 1059 return TensorConstMap<T, Range>(std::move(range), 1060 std::cref(btas::infinite_sequence_adaptor<const T*>(data))); 1061 } 1062 1063 /// Helper function that constructs TensorConstMap. 1064 /// \tparam Range the range type 1065 /// \param range the range object defining the view 1066 /// \return TensorView into \c storage using \c range 1067 /// \attention use make_cmap if you must force a const view; this will provide const view, however, if \c storage is a const reference. 1068 template <typename T, 1069 typename Range> 1070 TensorConstMap<typename std::remove_const<T>::type, Range> make_cmap(T * data,Range && range)1071 make_cmap(T* data, Range&& range) 1072 { 1073 typedef typename std::remove_const<T>::type value_type; 1074 typedef TensorConstMap<value_type, Range> result_type; 1075 return result_type(std::move(range), 1076 std::cref(btas::infinite_sequence_adaptor<const T*>(const_cast<const T*>(data)))); 1077 } 1078 1079 } // namespace btas 1080 1081 1082 #endif /* TENSORVIEW_H_ */ 1083