Advertisement
Guest User

Untitled

a guest
Jun 18th, 2019
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 65.91 KB | None | 0 0
  1. // Copyright (c) 2017-2018 Maikel Nadolski
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. // SOFTWARE.
  20.  
  21. #ifndef FUB_CORE_SPAN_HPP
  22. #define FUB_CORE_SPAN_HPP
  23.  
  24. #include <cassert>
  25. #include <array>
  26. #include <tuple>
  27. #include <type_traits>
  28. #include <experimental/type_traits>
  29.  
  30. namespace std::experimental {
  31.  
  32. inline constexpr std::ptrdiff_t dynamic_extent = -1;
  33.  
  34. /// \defgroup spans Spans
  35. /// Types and function which are about non-owning ranges of contiguous memory.
  36.  
  37. namespace detail {
  38. /// @{
  39. /// Tests if the specified type `T` is a `std::array<U, N>` for some U and N.
  40. template <typename T> struct is_std_array : std::false_type {};
  41. template <typename T, std::size_t N>
  42. struct is_std_array<std::array<T, N>> : std::true_type {};
  43. /// @}
  44.  
  45. template <typename T> using data_t = decltype(std::declval<T>().data());
  46. template <typename T> using element_type_ = std::remove_pointer_t<data_t<T>>;
  47. template <typename T> using array_type_t = element_type_<T> (*)[];
  48. } // namespace detail
  49.  
  50. template <typename T, std::ptrdiff_t N> class span;
  51.  
  52. ///////////////////////////////////////////////////////////////////////////////
  53. // [span.traits.is_span]
  54.  
  55. /// Returns true if the specified T is a `span<S, N>` for some type S and
  56. /// integer N.
  57. template <typename T> struct is_span : std::false_type {};
  58.  
  59. /// Returns true if the specified T is a `span<S, N>` for some type S and
  60. /// integer N.
  61. template <typename T, std::ptrdiff_t N>
  62. struct is_span<span<T, N>> : std::true_type {};
  63.  
  64. /// Returns true if the specified T is a `span<S, N>` for some type S and
  65. /// integer N.
  66. template <typename T> static constexpr bool is_span_v = is_span<T>::value;
  67.  
  68. ///////////////////////////////////////////////////////////////////////////////
  69. // [span.class]
  70.  
  71. /// \ingroup spans
  72. /// A span is a view over a contiguous sequence of objects, the storage of which
  73. /// is owned by some other object.
  74. ///
  75. /// All member functions of span have constant time complexity.
  76. ///
  77. /// `T` is required to be a complete object type that is not an abstract
  78. /// class type.
  79. ///
  80. /// If `N` is negative and not equal to dynamic_­extent, the program is
  81. /// ill-formed.
  82. template <typename T, std::ptrdiff_t N = dynamic_extent> class span {
  83. public:
  84. static_assert(N > 0, "span's extent needs to be non-negative.");
  85.  
  86. using element_type = T;
  87. using pointer = T*;
  88. using reference = T&;
  89. using value_type = std::remove_cv_t<T>;
  90. using index_type = std::ptrdiff_t;
  91. using difference_type = std::ptrdiff_t;
  92. using iterator = pointer;
  93. using const_iterator = std::add_const_t<T>*;
  94. using reverse_iterator = std::reverse_iterator<iterator>;
  95. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  96.  
  97. static constexpr index_type extent = N;
  98. static constexpr std::size_t sextent = static_cast<std::size_t>(N);
  99.  
  100. /// \name Constructors, copy, and assignment [span.cons]
  101.  
  102. /// Constructs a span from a `pointer` and `size` pair.
  103. ///
  104. /// This performs an assertion check in debug builds which will terminate the
  105. /// application if the specified size does not match the extent.
  106. ///
  107. /// \param[in] p a valid address pointing to the first element of the span.
  108. /// \param[in] size the size such that `[p, p + size)` is a valid range.
  109. ///
  110. /// \pre `size == extent`
  111. ///
  112. /// \post `data() == p`
  113. /// \post `size() == size`
  114. ///
  115. /// \throws Nothing.
  116. constexpr span(pointer p, [[maybe_unused]] index_type size) : pointer_{p} {
  117. assert(size == extent);
  118. }
  119.  
  120. /// Constructs a span from two pointers.
  121. ///
  122. /// This performs an assertion check in debug builds which will terminate the
  123. /// application if the specified size does not match the extent.
  124. ///
  125. /// \param[in] first a valid address pointing to the first element of the
  126. /// span. \param[in] last a pointer such that `[first, last)` is a valid
  127. /// range.
  128. ///
  129. /// \pre `last - first == extent`
  130. ///
  131. /// \post `data() == first`
  132. /// \post `size() == last - first`
  133. ///
  134. /// \throws Nothing.
  135. constexpr span(pointer first, pointer last) : span(first, last - first) {}
  136.  
  137. /// Implicit conversion from a built-in C-style array.
  138. ///
  139. /// \param[in] arr A native array which will be viewed on.
  140. ///
  141. /// \post `data() = &arr[0]`
  142. /// \post `size() == extent`
  143. ///
  144. /// \throws Nothing.
  145. constexpr span(element_type (&arr)[sextent]) noexcept // NOLINT
  146. : pointer_{&arr[0]} {}
  147.  
  148. /// Implicit conversion from const `std::array`s.
  149. ///
  150. /// \param[in] arr A `std::array` which will be viewed on.
  151. ///
  152. /// \pre `std::is_const<element_type>`
  153. ///
  154. /// \post `data() = arr.data()`
  155. /// \post `size() == extent`
  156. ///
  157. /// \throws Nothing.
  158. template <typename ValueType, std::size_t Extent,
  159. typename = std::enable_if_t<Extent == extent>,
  160. typename = std::enable_if_t<std::is_convertible<
  161. const ValueType (*)[], element_type (*)[]>::value>>
  162. constexpr span(const std::array<ValueType, Extent>& arr) noexcept // NOLINT
  163. : pointer_{arr.data()} {}
  164.  
  165. /// Implicit conversion from mutable `std::array`s.
  166. ///
  167. /// \param[in] arr A `std::array` which will be viewed on.
  168. ///
  169. /// \pre `M == extent`
  170. ///
  171. /// \post `data() = arr.data()`
  172. /// \post `size() == extent`
  173. ///
  174. /// \throws Nothing.
  175. template <typename ValueType, std::size_t Extent,
  176. typename = std::enable_if_t<Extent == extent>,
  177. typename = std::enable_if_t<std::is_convertible<
  178. ValueType (*)[], element_type (*)[]>::value>>
  179. constexpr span(std::array<ValueType, Extent>& arr) noexcept // NOLINT
  180. : pointer_{arr.data()} {}
  181.  
  182. /// Implicit conversion operator from a mutable container.
  183. ///
  184. /// \param[in] container A container which owns the contiguous memory. The
  185. /// container must outlive this span, otherwise the span is
  186. /// dangling.
  187. ///
  188. /// \tparam Container A container class which has the class member functions
  189. /// `Container::data()` and `Container::size()`.
  190. ///
  191. /// \pre `container.size() == extent`
  192. /// \pre `!is_span_v<Container>`
  193. ///
  194. /// \post `data() == container.data()`
  195. /// \post `size() == container.size() == extent`
  196. ///
  197. /// \throws Nothing.
  198. #ifdef DOXYGEN
  199. template <typename Container>
  200. #else
  201. template <typename Container,
  202. typename = std::enable_if_t<!std::is_array<Container>::value>,
  203. typename = std::enable_if_t<
  204. !detail::is_std_array<std::remove_const_t<Container>>::value>,
  205. typename = std::enable_if_t<!is_span<Container>::value>,
  206. typename = std::enable_if_t<std::is_convertible<
  207. detected_t<detail::array_type_t, Container&>,
  208. element_type (*)[]>::value>>
  209. #endif
  210. constexpr span(Container& container) // NOLINT
  211. : pointer_{container.data()} {
  212. assert(container.size() == extent);
  213. }
  214.  
  215. /// Implicit conversion operator from a constant container.
  216. ///
  217. /// \param[in] container A container which owns the contiguous memory. The
  218. /// container must outlive this span, otherwise the span is
  219. /// dangling.
  220. ///
  221. /// \tparam Container A container class which has the class member functions
  222. /// `Container::data()` and `Container::size()`.
  223. ///
  224. /// \pre `extent <= container.size()`
  225. /// \pre `!is_span_v<Container>`
  226. ///
  227. /// \post `data() == container.data()`
  228. /// \post `size() == container.size() == extent`
  229. ///
  230. /// \throws Nothing.
  231. #ifdef DOXYGEN
  232. template <typename Container>
  233. #else
  234. template <
  235. typename Container,
  236. typename = std::enable_if_t<!std::is_array<Container>::value>,
  237. typename = std::enable_if_t<!detail::is_std_array<Container>::value>,
  238. typename = std::enable_if_t<!is_span<Container>::value>,
  239. typename = std::enable_if_t<std::is_convertible<
  240. detected_t<detail::array_type_t, const Container&>,
  241. element_type (*)[]>::value>>
  242. #endif
  243. constexpr span(const Container& container) // NOLINT
  244. : pointer_{container.data()} {
  245. assert(container.size() == extent);
  246. }
  247.  
  248. /// Implicit conversion from other span types.
  249. ///
  250. /// \tparam S the element type of the other span.
  251. /// \tparam M the static extents of the other span.
  252. ///
  253. /// \pre s.size() == extent
  254. /// \pre std::is_convertible<S(*)[], T(*)[]>::value
  255. ///
  256. /// \post `data() == s.data()`
  257. /// \post `size() == s.size() == extent`.
  258. #ifdef DOXYGEN
  259. template <typename S, std::ptrdiff_t M>
  260. #else
  261. template <
  262. typename S, std::ptrdiff_t M,
  263. typename = std::enable_if_t<std::is_convertible<
  264. typename span<S, M>::element_type (*)[], element_type (*)[]>::value>,
  265. typename = std::enable_if_t<extent == M>>
  266. #endif
  267. constexpr span(const span<S, M>& s) noexcept // NOLINT
  268. : pointer_{s.data()} {
  269. }
  270.  
  271. template <
  272. typename S,
  273. typename = std::enable_if_t<std::is_convertible<
  274. typename span<S>::element_type (*)[], element_type (*)[]>::value>>
  275. constexpr span(const span<S>& s) // NOLINT
  276. : pointer_{s.data()} {
  277. assert(s.size() == extent);
  278. }
  279.  
  280. /// Defaulted copy constructor to trivially copy the class member variables.
  281. ///
  282. /// \throws Nothing.
  283. constexpr span(const span& s) noexcept = default;
  284.  
  285. /// \name Subviews [span.sub]
  286.  
  287. /// Returns a span of the first `Count`-many elements of this span.
  288. ///
  289. /// \tparam Count Size of the returned subspan.
  290. ///
  291. /// \pre `0 <= Count && Count <= extent`.
  292. ///
  293. /// \throws Nothing.
  294. template <ptrdiff_t Count,
  295. typename = std::enable_if_t<(0 <= Count && Count <= extent)>>
  296. constexpr span<element_type, Count> first() const {
  297. return {pointer_, Count};
  298. }
  299.  
  300. /// Returns a span of the first `count`-many elements of this span.
  301. ///
  302. /// \param[in] count Size of the returned subspan.
  303. ///
  304. /// \pre `0 <= count && count <= extent`.
  305. ///
  306. /// \throws Nothing.
  307. constexpr span<element_type> first(index_type count) const {
  308. assert(0 <= count && count <= size());
  309. return {pointer_, count};
  310. }
  311.  
  312. /// Returns a span of the last `Count`-many elements of this span.
  313. ///
  314. /// \tparam Count Size of the returned subspan.
  315. ///
  316. /// \pre `0 <= Count && Count <= extent`.
  317. ///
  318. /// \throws Nothing.
  319. template <ptrdiff_t Count,
  320. typename = std::enable_if_t<(0 <= Count && Count <= extent)>>
  321. constexpr span<element_type, Count> last() const {
  322. return {pointer_ + (extent - Count), Count};
  323. }
  324.  
  325. /// Returns a span of the last `count`-many elements of this span.
  326. ///
  327. /// \param[in] count Size of the returned subspan.
  328. ///
  329. /// \pre `0 <= count && count <= extent`.
  330. ///
  331. /// \throws Nothing.
  332. constexpr span<element_type> last(index_type count) const {
  333. assert(0 <= count && count <= extent);
  334. return {pointer_ + (extent - count), count};
  335. }
  336.  
  337. /// Returns a subspan viewing `Count` many elements from offset `Offset`.
  338. ///
  339. /// \tparam Offset the offset of the returned subspan.
  340. /// \tparam Count Size of the returned subspan.
  341. ///
  342. /// \pre `0 <= Count && Count <= extent`.
  343. ///
  344. /// \throws Nothing.
  345. template <
  346. ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent,
  347. typename = std::enable_if_t<(0 <= Offset && Offset <= extent)>,
  348. typename = std::enable_if_t<(Count == dynamic_extent ||
  349. (0 <= Count && Count + Offset <= extent))>>
  350. constexpr auto subspan() const {
  351. #ifndef __cpp_if_constexpr
  352. struct if_constexpr_t_ {
  353. auto operator()(std::true_type, pointer p) {
  354. return span<T, extent - Offset>{p + Offset, extent - Offset};
  355. }
  356. auto operator()(std::false_type, pointer p) {
  357. return span<T, Count>{p + Offset, Count};
  358. }
  359. } if_constexpr_{};
  360. return if_constexpr_(Count == dynamic_extent, pointer_, extent);
  361. #else
  362. if constexpr (Count == dynamic_extent) {
  363. return span<T, extent - Offset>{pointer_ + Offset, extent - Offset};
  364. } else {
  365. return span<T, Count>{pointer_ + Offset, Count};
  366. }
  367. #endif
  368. }
  369.  
  370. /// Returns a subspan viewing `count` many elements from offset `offset`.
  371. ///
  372. /// \param offset the offset of the returned subspan.
  373. /// \param count Size of the returned subspan.
  374. ///
  375. /// \pre `0 <= offset && offset <= extent`.
  376. /// \pre `count == dynamic_extent || 0 <= count && count + offset <= size()`.
  377. ///
  378. /// \throws Nothing.
  379. constexpr span<element_type>
  380. subspan(index_type offset, index_type count = dynamic_extent) const {
  381. assert(0 <= offset && offset <= size());
  382. assert(count == dynamic_extent ||
  383. (0 <= count && count + offset <= size()));
  384. return {pointer_ + offset,
  385. count == dynamic_extent ? size() - offset : count};
  386. }
  387.  
  388. /// \name Observers [span.obs]
  389.  
  390. /// Returns the number of elements in the span.
  391. ///
  392. /// \throws Nothing.
  393. constexpr index_type size() const noexcept { return extent; }
  394.  
  395. /// Returns the number of bytes which are spanned by this span.
  396. ///
  397. /// \throws Nothing.
  398. constexpr index_type size_bytes() const noexcept {
  399. return sizeof(T) * extent;
  400. }
  401.  
  402. /// Returns true if `size() == 0`.
  403. ///
  404. /// \throws Nothing.
  405. constexpr bool empty() const noexcept { return false; }
  406.  
  407. /// \name Element access [span.elem]
  408.  
  409. /// Returns the underlying pointer.
  410. ///
  411. /// \throws Nothing.
  412. constexpr pointer data() const noexcept { return pointer_; }
  413.  
  414. /// Accesses the n-th element of the spanned array.
  415. ///
  416. /// \throws Nothing.
  417. constexpr reference operator[](index_type n) const { return pointer_[n]; }
  418.  
  419. /// Accesses the n-th element of the spanned array.
  420. ///
  421. /// \throws Nothing.
  422. constexpr reference operator()(index_type n) const { return pointer_[n]; }
  423.  
  424. /// \name Iterator support [span.iterators]
  425.  
  426. /// Returns an iterator pointing to the first element of the span.
  427. ///
  428. /// \throws Nothing.
  429. constexpr iterator begin() const noexcept { return pointer_; }
  430.  
  431. /// Returns a const iterator pointing to the first element of the span.
  432. ///
  433. /// \throws Nothing.
  434. constexpr const_iterator cbegin() const noexcept { return pointer_; }
  435.  
  436. /// Returns an iterator pointing one after the last element of the span.
  437. ///
  438. /// \throws Nothing.
  439. constexpr iterator end() const noexcept { return pointer_ + extent; }
  440.  
  441. /// Returns a const iterator pointing one after the last element of the span.
  442. ///
  443. /// \throws Nothing.
  444. constexpr const_iterator cend() const noexcept { return pointer_ + extent; }
  445.  
  446. /// Returns a reverse iterator pointing to the last element of the span.
  447. ///
  448. /// \throws Nothing.
  449. constexpr reverse_iterator rbegin() const noexcept {
  450. return reverse_iterator(end());
  451. }
  452.  
  453. /// Returns a const reverse iterator pointing to the last element of the span.
  454. ///
  455. /// \throws Nothing.
  456. constexpr const_reverse_iterator crbegin() const noexcept {
  457. return const_reverse_iterator(cend());
  458. }
  459.  
  460. /// Returns a reverse iterator pointing to the first element of the span.
  461. ///
  462. /// \throws Nothing.
  463. constexpr reverse_iterator rend() const noexcept {
  464. return reverse_iterator(begin());
  465. }
  466.  
  467. /// Returns a const reverse iterator pointing to the first element of the
  468. /// span.
  469. ///
  470. /// \throws Nothing.
  471. constexpr const_reverse_iterator crend() const noexcept {
  472. return const_reverse_iterator(cbegin());
  473. }
  474.  
  475. private:
  476. pointer pointer_;
  477. };
  478.  
  479. /// \ingroup spans
  480. /// A span is a view over a contiguous sequence of objects, the storage of which
  481. /// is owned by some other object.
  482. ///
  483. /// All member functions of span have constant time complexity.
  484. ///
  485. /// `T` is required to be a complete object type that is not an abstract
  486. /// class type.
  487. ///
  488. /// If `N` is negative and not equal to dynamic_­extent, the program is
  489. /// ill-formed.
  490. template <typename T> class span<T, 0> {
  491. public:
  492. using element_type = T;
  493. using pointer = T*;
  494. using reference = T&;
  495. using value_type = std::remove_cv_t<T>;
  496. using index_type = std::ptrdiff_t;
  497. using difference_type = std::ptrdiff_t;
  498. using iterator = pointer;
  499. using const_iterator = std::add_const_t<T>*;
  500. using reverse_iterator = std::reverse_iterator<iterator>;
  501. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  502.  
  503. static constexpr index_type extent = 0;
  504.  
  505. /// \name Constructors, copy, and assignment [span.cons]
  506.  
  507. /// Constructs an empty span.
  508. ///
  509. /// \post `data() == nullptr`
  510. /// \post `size() == 0`
  511. ///
  512. /// \throws Nothing.
  513. constexpr span() noexcept = default;
  514.  
  515. /// Constructs a span from a `pointer` + `size` pair.
  516. ///
  517. /// This performs an assertion check in debug builds which will terminate the
  518. /// application if the specified size does not match the extent.
  519. ///
  520. /// \pre `p` is a valid pointer.
  521. /// \pre `size == 0`
  522. ///
  523. /// \post `data() == p`
  524. /// \post `size() == 0`
  525. ///
  526. /// \throws Nothing.
  527. constexpr span(pointer p, [[maybe_unused]] index_type size) : pointer_{p} {
  528. assert(size == 0);
  529. }
  530.  
  531. /// Constructs a span from two `pointer`s.
  532. ///
  533. /// This performs an assertion check in debug builds which will terminate the
  534. /// application if the specified size does not match the extent.
  535. ///
  536. /// \pre `first` and `last` are valid pointers.
  537. /// \pre `first == last`
  538. ///
  539. /// \post `data() == first`
  540. /// \post `size() == last - first`
  541. ///
  542. /// \throws Nothing.
  543. constexpr span(pointer first, pointer last) : span(first, last - first) {}
  544.  
  545. /// Implicit conversion operator from a mutable container.
  546. ///
  547. /// \pre `container.size() == extent`
  548. /// \pre `!is_span_v<Container>`
  549. /// \pre `container.size() == 0`
  550. ///
  551. /// \post `data() == container.data()`
  552. /// \post `size() == container.size()`
  553. ///
  554. /// \throws Nothing.
  555. #ifdef DOXYGEN
  556. template <typename Container>
  557. #else
  558. template <typename Container,
  559. typename = std::enable_if_t<!std::is_array<Container>::value>,
  560. typename = std::enable_if_t<!is_span<Container>::value>,
  561. typename = std::enable_if_t<
  562. std::is_convertible<detected_t<detail::array_type_t, Container>,
  563. element_type (*)[]>::value>>
  564. #endif
  565. constexpr span(Container& container) // NOLINT
  566. : pointer_{container.data()} {
  567. assert(container.size() == extent);
  568. }
  569.  
  570. /// Implicit conversion operator from a constant container.
  571. ///
  572. /// \pre `extent <= container.size()`
  573. /// \pre `!is_span_v<Container>`
  574. /// \pre `container.size() == 0`
  575. ///
  576. /// \post `data() == container.data()`
  577. /// \post `size() == container.size()`
  578. ///
  579. /// \throws Nothing.
  580. #ifdef DOXYGEN
  581. template <typename Container>
  582. #else
  583. template <typename Container,
  584. typename = std::enable_if_t<!std::is_array<Container>::value>,
  585. typename = std::enable_if_t<!is_span<Container>::value>,
  586. typename = std::enable_if_t<
  587. std::is_convertible<detected_t<detail::array_type_t, Container>,
  588. element_type (*)[]>::value>>
  589. #endif
  590. constexpr span(const Container& container) // NOLINT
  591. : pointer_{container.data()} {
  592. assert(container.size() == extent);
  593. }
  594.  
  595. /// Implicit conversion from other span types.
  596. ///
  597. /// \pre std::is_convertible<S(*)[], T(*)[]>::value
  598. ///
  599. /// \post data() == s.data()
  600. ///
  601. /// \throws Nothing.
  602. #ifdef DOXYGEN
  603. template <typename S>
  604. #else
  605. template <
  606. typename S,
  607. typename = std::enable_if_t<std::is_convertible<
  608. typename span<S, 0>::element_type (*)[], element_type (*)[]>::value>>
  609. #endif
  610. constexpr span(const span<S, 0>& s) noexcept // NOLINT
  611. : pointer_{s.data()} {
  612. }
  613.  
  614. /// Defaulted copy constructor to trivially copy the class member variables.
  615. ///
  616. /// \throws Nothing.
  617. constexpr span(const span& s) noexcept = default;
  618.  
  619. /// \name Observers [span.obs]
  620.  
  621. /// Returns the number of elements in the span.
  622. ///
  623. /// \throws Nothing.
  624. constexpr index_type size() const noexcept { return 0; }
  625.  
  626. /// Returns the number of bytes which are spanned by this span.
  627. ///
  628. /// \throws Nothing.
  629. constexpr std::ptrdiff_t size_bytes() const noexcept { return 0; }
  630.  
  631. /// Returns true if `size() == 0`.
  632. ///
  633. /// \throws Nothing.
  634. constexpr bool empty() const noexcept { return true; }
  635.  
  636. /// \name Element access [span.elem]
  637.  
  638. /// Returns the underlying pointer.
  639. ///
  640. /// \throws Nothing.
  641. constexpr pointer data() const noexcept { return pointer_; }
  642.  
  643. /// \name Iterator support [span.iterators]
  644.  
  645. /// Returns an iterator pointing to the first element of the span.
  646. ///
  647. /// \throws Nothing.
  648. constexpr iterator begin() const noexcept { return data(); }
  649.  
  650. /// Returns a const iterator pointing to the first element of the span.
  651. ///
  652. /// \throws Nothing.
  653. constexpr const_iterator cbegin() const noexcept { return data(); }
  654.  
  655. /// Returns an iterator pointing one after the last element of the span.
  656. ///
  657. /// \throws Nothing.
  658. constexpr iterator end() const noexcept { return begin() + size(); }
  659.  
  660. /// Returns a const iterator pointing one after the last element of the span.
  661. ///
  662. /// \throws Nothing.
  663. constexpr const_iterator cend() const noexcept { return begin() + size(); }
  664.  
  665. /// Returns a reverse iterator pointing to the last element of the span.
  666. ///
  667. /// \throws Nothing.
  668. constexpr reverse_iterator rbegin() const noexcept {
  669. return reverse_iterator(end());
  670. }
  671.  
  672. /// Returns a const reverse iterator pointing to the last element of the span.
  673. ///
  674. /// \throws Nothing.
  675. constexpr const_reverse_iterator crbegin() const noexcept {
  676. return const_reverse_iterator(cend());
  677. }
  678.  
  679. /// Returns a reverse iterator pointing to the first element of the span.
  680. ///
  681. /// \throws Nothing.
  682. constexpr reverse_iterator rend() const noexcept {
  683. return reverse_iterator(begin());
  684. }
  685.  
  686. /// Returns a const reverse iterator pointing to the first element of the
  687. /// span.
  688. ///
  689. /// \throws Nothing.
  690. constexpr const_reverse_iterator crend() const noexcept {
  691. return const_reverse_iterator(cbegin());
  692. }
  693.  
  694. private:
  695. pointer pointer_{nullptr};
  696. };
  697.  
  698. /// \ingroup spans
  699. /// span is a compact view over a contiguous range of data.
  700. ///
  701. /// This class models something like
  702. ///
  703. /// \code struct span { pointer ptr; std::ptrdiff_t length; }; \endcode
  704. ///
  705. /// Where the `length` can be omitted for statically sized views.
  706. template <typename T> class span<T, dynamic_extent> {
  707. public:
  708. using element_type = T;
  709. using pointer = T*;
  710. using reference = T&;
  711. using value_type = std::remove_cv_t<T>;
  712. using index_type = std::ptrdiff_t;
  713. using difference_type = std::ptrdiff_t;
  714. using iterator = pointer;
  715. using const_iterator = std::add_const_t<T>*;
  716. using reverse_iterator = std::reverse_iterator<iterator>;
  717. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  718.  
  719. static constexpr index_type extent = dynamic_extent;
  720.  
  721. /////////////////////////////////////////////////////////////////////////////
  722. // Constructors
  723.  
  724. /// Constructs an empty span of size 0.
  725. ///
  726. /// This initializes the underlying pointer to nullptr and the size to 0.
  727. ///
  728. /// \throws Nothing.
  729. ///
  730. /// \post data() == nullptr
  731. /// \post size() == 0
  732. constexpr span() = default;
  733.  
  734. /// Constructs a span from a `pointer` + `size` pair.
  735. ///
  736. /// This performs an assertion check in debug builds which will terminate the
  737. /// application if the specified size does not match the extent.
  738. ///
  739. /// \throws Nothing.
  740. ///
  741. /// \post data() == p
  742. /// \post size() == size
  743. constexpr span(pointer p, index_type size) noexcept
  744. : pointer_{p}, size_{size} {}
  745.  
  746. /// Constructs a span from two `pointer`s.
  747. ///
  748. /// This performs an assertion check in debug builds which will terminate the
  749. /// application if the specified size does not match the extent.
  750. ///
  751. /// \throws Nothing.
  752. ///
  753. /// \post data() == first
  754. /// \post size() == last - first
  755. constexpr span(pointer first, pointer last) noexcept
  756. : pointer_{first}, size_{last - first} {}
  757.  
  758. /// Implicit conversion from a built-in C-style array.
  759. ///
  760. /// \throws Nothing.
  761. ///
  762. /// \post data() = pointer(&arr[0])
  763. /// \post size() == M
  764. template <std::size_t M>
  765. constexpr span(element_type (&arr)[M]) noexcept // NOLINT
  766. : pointer_{&arr[0]}, size_{static_cast<index_type>(M)} {}
  767.  
  768. /// Implicit conversion from mutable Container-like types.
  769. ///
  770. /// \pre S(*)[] is convertible to element_type(*)[]
  771. ///
  772. /// \throws Nothing.
  773. ///
  774. /// \post data() = container.data()
  775. /// \post size() = container.size()
  776. template <
  777. typename Container,
  778. typename = std::enable_if_t<!std::is_array<Container>::value>,
  779. typename =
  780. std::enable_if_t<!is_span<std::remove_const_t<Container>>::value>,
  781. typename = std::enable_if_t<
  782. std::is_convertible<detected_t<detail::array_type_t, Container&>,
  783. element_type (*)[]>::value>>
  784. constexpr span(Container& container) noexcept // NOLINT
  785. : pointer_{container.data()}, size_{static_cast<index_type>(
  786. container.size())} {}
  787.  
  788. /// Implicit conversion from other span types.
  789. ///
  790. /// \pre size() <= M
  791. /// \pre std::is_convertible<S(*)[], T(*)[]>::value
  792. ///
  793. /// \post data() == s.data()
  794. template <
  795. typename S, index_type OtherExtents,
  796. typename = std::enable_if_t<std::is_convertible<S (*)[], T (*)[]>::value>>
  797. constexpr span(const span<S, OtherExtents>& s) noexcept // NOLINT
  798. : pointer_{s.data()}, size_{s.size()} {}
  799.  
  800. constexpr span(const span& s) noexcept = default;
  801.  
  802. /// \name Subviews [span.sub]
  803.  
  804. /// Returns a span of the first `Count`-many elements of this span.
  805. ///
  806. /// \tparam Count Size of the returned subspan.
  807. ///
  808. /// \pre `0 <= Count && Count <= extent`.
  809. ///
  810. /// \throws Nothing.
  811. template <ptrdiff_t Count, typename = std::enable_if_t<0 <= Count>>
  812. constexpr span<element_type, Count> first() const {
  813. assert(Count <= size());
  814. return {pointer_, Count};
  815. }
  816.  
  817. /// Returns a span of the first `count`-many elements of this span.
  818. ///
  819. /// \param[in] count Size of the returned subspan.
  820. ///
  821. /// \pre `0 <= count && count <= extent`.
  822. ///
  823. /// \throws Nothing.
  824. constexpr span<element_type> first(index_type count) const {
  825. assert(0 <= count && count <= size());
  826. return {pointer_, count};
  827. }
  828.  
  829. /// Returns a span of the last `Count`-many elements of this span.
  830. ///
  831. /// \tparam Count Size of the returned subspan.
  832. ///
  833. /// \pre `0 <= Count && Count <= extent`.
  834. ///
  835. /// \throws Nothing.
  836. template <ptrdiff_t Count, typename = std::enable_if_t<0 <= Count>>
  837. constexpr span<element_type, Count> last() const {
  838. assert(Count <= size());
  839. return {pointer_ + (size() - Count), Count};
  840. }
  841.  
  842. /// Returns a span of the last `count`-many elements of this span.
  843. ///
  844. /// \param[in] count Size of the returned subspan.
  845. ///
  846. /// \pre `0 <= count && count <= extent`.
  847. ///
  848. /// \throws Nothing.
  849. constexpr span<element_type> last(index_type count) const {
  850. assert(0 <= count && count <= size());
  851. return {pointer_ + (extent - count), count};
  852. }
  853.  
  854. /// Returns a subspan viewing `Count` many elements from offset `Offset`.
  855. ///
  856. /// \tparam Offset the offset of the returned subspan.
  857. /// \tparam Count Size of the returned subspan.
  858. ///
  859. /// \pre `0 <= Count && Count <= extent`.
  860. ///
  861. /// \throws Nothing.
  862. template <ptrdiff_t Offset, ptrdiff_t Count = dynamic_extent,
  863. typename = std::enable_if_t<0 <= Offset>>
  864. constexpr span<element_type, Count> subspan() const {
  865. assert(Offset <= size());
  866. assert(Count == dynamic_extent ||
  867. (0 <= Count && Count + Offset <= size()));
  868. return {pointer_ + Offset,
  869. Count == dynamic_extent ? size() - Offset : Count};
  870. }
  871.  
  872. /// Returns a subspan viewing `count` many elements from offset `offset`.
  873. ///
  874. /// \param offset the offset of the returned subspan.
  875. /// \param count Size of the returned subspan.
  876. ///
  877. /// \pre `0 <= offset && offset <= extent`.
  878. /// \pre `count == dynamic_extent || 0 <= count && count + offset <= size()`.
  879. ///
  880. /// \throws Nothing.
  881. constexpr span<element_type>
  882. subspan(index_type offset, index_type count = dynamic_extent) const {
  883. assert(0 <= offset && offset <= size());
  884. assert(count == dynamic_extent ||
  885. (0 <= count && count + offset <= size()));
  886. return {pointer_ + offset,
  887. count == dynamic_extent ? size() - offset : count};
  888. }
  889.  
  890. /// \name Observers [span.obs]
  891.  
  892. /// Returns the number of elements in the span.
  893. ///
  894. /// \throws Nothing.
  895. constexpr index_type size() const noexcept { return size_; }
  896.  
  897. /// Returns the number of bytes which are spanned by this span.
  898. ///
  899. /// \throws Nothing.
  900. constexpr index_type size_bytes() const noexcept { return sizeof(T) * size_; }
  901.  
  902. /// Returns true if `size() == 0`.
  903. ///
  904. /// \throws Nothing.
  905. constexpr bool empty() const noexcept { return size_ == 0; }
  906.  
  907. /// \name Element access [span.elem]
  908.  
  909. /// Returns the underlying pointer.
  910. ///
  911. /// \throws Nothing.
  912. constexpr pointer data() const noexcept { return pointer_; }
  913.  
  914. /// Accesses the n-th element of the spanned array.
  915. ///
  916. /// \throws Nothing.
  917. constexpr reference operator[](index_type n) const { return pointer_[n]; }
  918.  
  919. /// Accesses the n-th element of the spanned array.
  920. ///
  921. /// \throws Nothing.
  922. constexpr reference operator()(index_type n) const { return pointer_[n]; }
  923.  
  924. /// \name Iterator support [span.iterators]
  925.  
  926. /// Returns an iterator pointing to the first element of the span.
  927. ///
  928. /// \throws Nothing.
  929. constexpr iterator begin() const noexcept { return pointer_; }
  930.  
  931. /// Returns a const iterator pointing to the first element of the span.
  932. ///
  933. /// \throws Nothing.
  934. constexpr const_iterator cbegin() const noexcept { return pointer_; }
  935.  
  936. /// Returns an iterator pointing one after the last element of the span.
  937. ///
  938. /// \throws Nothing.
  939. constexpr iterator end() const noexcept { return pointer_ + size_; }
  940.  
  941. /// Returns a const iterator pointing one after the last element of the span.
  942. ///
  943. /// \throws Nothing.
  944. constexpr const_iterator cend() const noexcept { return pointer_ + size_; }
  945.  
  946. /// Returns a reverse iterator pointing to the last element of the span.
  947. ///
  948. /// \throws Nothing.
  949. constexpr reverse_iterator rbegin() const noexcept {
  950. return reverse_iterator(end());
  951. }
  952.  
  953. /// Returns a const reverse iterator pointing to the last element of the span.
  954. ///
  955. /// \throws Nothing.
  956. constexpr const_reverse_iterator crbegin() const noexcept {
  957. return const_reverse_iterator(cend());
  958. }
  959.  
  960. /// Returns a reverse iterator pointing to the first element of the span.
  961. ///
  962. /// \throws Nothing.
  963. constexpr reverse_iterator rend() const noexcept {
  964. return reverse_iterator(begin());
  965. }
  966.  
  967. /// Returns a const reverse iterator pointing to the first element of the
  968. /// span.
  969. ///
  970. /// \throws Nothing.
  971. constexpr const_reverse_iterator crend() const noexcept {
  972. return const_reverse_iterator(cbegin());
  973. }
  974.  
  975. private:
  976. pointer pointer_{nullptr};
  977. index_type size_{0};
  978. };
  979.  
  980. //#ifdef __cpp_deduction_guides
  981.  
  982. template <class T, typename I> span(T*, I)->span<T>;
  983.  
  984. template <class T, size_t N>
  985. span(T (&)[N])->span<T, static_cast<std::ptrdiff_t>(N)>;
  986.  
  987. template <class T, size_t N>
  988. span(std::array<T, N>&)->span<T, static_cast<std::ptrdiff_t>(N)>;
  989.  
  990. template <class T, size_t N>
  991. span(const std::array<T, N>&)->span<const T, static_cast<std::ptrdiff_t>(N)>;
  992.  
  993. template <class Container>
  994. span(Container&)->span<typename Container::value_type>;
  995.  
  996. template <class Container>
  997. span(const Container&)->span<const typename Container::value_type>;
  998.  
  999. //#endif
  1000.  
  1001. template <class T, size_t N>
  1002. auto make_span(T (&array)[N]) -> span<T, static_cast<std::ptrdiff_t>(N)> {
  1003. return span<T, static_cast<std::ptrdiff_t>(N)>(array);
  1004. }
  1005.  
  1006. template <class T, size_t N>
  1007. auto make_span(std::array<T, N>& array)
  1008. -> span<T, static_cast<std::ptrdiff_t>(N)> {
  1009. return span<T, static_cast<std::ptrdiff_t>(N)>(array);
  1010. }
  1011.  
  1012. template <class T, size_t N>
  1013. auto make_span(const std::array<T, N>& array)
  1014. -> span<const T, static_cast<std::ptrdiff_t>(N)> {
  1015. return span<const T, static_cast<std::ptrdiff_t>(N)>(array);
  1016. }
  1017.  
  1018. template <class Container>
  1019. auto make_span(Container& array) -> span<typename Container::value_type> {
  1020. return span<typename Container::value_type>(array);
  1021. }
  1022.  
  1023. template <class Container>
  1024. auto make_span(const Container& array)
  1025. -> span<const typename Container::value_type> {
  1026. return span<const typename Container::value_type>(array);
  1027. }
  1028.  
  1029. }
  1030.  
  1031. #endif // !SPAN_HPP
  1032.  
  1033.  
  1034. // Copyright (c) 2018 Maikel Nadolski
  1035. //
  1036. // Permission is hereby granted, free of charge, to any person obtaining a copy
  1037. // of this software and associated documentation files (the "Software"), to deal
  1038. // in the Software without restriction, including without limitation the rights
  1039. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  1040. // copies of the Software, and to permit persons to whom the Software is
  1041. // furnished to do so, subject to the following conditions:
  1042. //
  1043. // The above copyright notice and this permission notice shall be included in
  1044. // all copies or substantial portions of the Software.
  1045. //
  1046. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1047. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1048. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1049. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1050. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  1051. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  1052. // SOFTWARE.
  1053.  
  1054. /// @file This file introduces `extents<E0, ..., En>`, a compact
  1055. /// multi-dimensional size type. Each integral extent `Ei` stands an upper bound
  1056. /// in dimension `i` and can either be a compile-time constant signed integral
  1057. /// value or `dynamic_extent`. Each compile-time sized extent does not take any
  1058. /// extra byte.
  1059.  
  1060. #ifndef FUB_CORE_MDSPAN_HPP
  1061. #define FUB_CORE_MDSPAN_HPP
  1062.  
  1063. namespace std::experimental {
  1064. /// This is the storage type for the extents class and only takes storage for
  1065. /// dynamic extents.
  1066. ///
  1067. /// This class is also responsible for accessing all extents.
  1068. template <std::size_t Rank, std::size_t DynamicRank,
  1069. std::ptrdiff_t... StaticExtents>
  1070. class ExtentsStorage_;
  1071.  
  1072. /// This is the class template specialisation if all extents are statically
  1073. /// known.
  1074. ///
  1075. /// In this case no extra storage is going to be used.
  1076. template <std::size_t Rank, std::ptrdiff_t... StaticExtents>
  1077. class ExtentsStorage_<Rank, 0, StaticExtents...> {
  1078. public:
  1079. static_assert(Rank == sizeof...(StaticExtents),
  1080. "Rank does not match sizeof...(StaticExtents)!");
  1081.  
  1082. // [mdspan.extents.obs], Observers of the domain multi-index space
  1083.  
  1084. /// Returns sizeof...(StaticExtents)
  1085. static constexpr std::size_t rank() noexcept { return Rank; }
  1086.  
  1087. /// Returns 0.
  1088. static constexpr std::size_t rank_dynamic() noexcept { return 0; }
  1089.  
  1090. /// Returns the n-th Static Extent.
  1091. static constexpr std::ptrdiff_t static_extent(std::size_t n) noexcept {
  1092. const std::ptrdiff_t static_extents[Rank]{StaticExtents...};
  1093. return static_extents[n];
  1094. }
  1095.  
  1096. /// Returns the N-th Extent.
  1097. ///
  1098. /// In this case where all extents are known at compile time, this returns
  1099. /// `static_extent(n)`.
  1100. constexpr std::ptrdiff_t extent(size_t n) const noexcept {
  1101. return static_extent(n);
  1102. }
  1103. };
  1104.  
  1105. template <std::size_t Rank, std::ptrdiff_t... StaticExtents>
  1106. class ExtentsStorage_<Rank, Rank, StaticExtents...> {
  1107. public:
  1108. static_assert(Rank == sizeof...(StaticExtents),
  1109. "Rank does not match sizeof...(StaticExtents)!");
  1110.  
  1111. // [mdspan.extents.constructors]
  1112.  
  1113. ExtentsStorage_() = default;
  1114.  
  1115. template <typename... IndexType,
  1116. typename = std::enable_if_t<conjunction<
  1117. std::is_convertible<IndexType, std::ptrdiff_t>...>::value>,
  1118. typename = std::enable_if_t<sizeof...(IndexType) == Rank>>
  1119. constexpr explicit ExtentsStorage_(IndexType... extent) noexcept
  1120. : m_dynamic_extents{static_cast<std::ptrdiff_t>(extent)...} {}
  1121.  
  1122. constexpr explicit ExtentsStorage_(
  1123. const std::array<std::ptrdiff_t, Rank>& extents) noexcept
  1124. : m_dynamic_extents{extents} {}
  1125.  
  1126. // [mdspan.extents.obs], Observers of the domain multi-index space
  1127.  
  1128. /// Returns sizeof...(StaticExtents)
  1129. static constexpr std::size_t rank() noexcept { return Rank; }
  1130.  
  1131. /// Returns sizeof...(StaticExtents)
  1132. static constexpr std::size_t rank_dynamic() noexcept { return Rank; }
  1133.  
  1134. /// Returns dynamic_extent.
  1135. static constexpr std::ptrdiff_t static_extent(std::size_t /* n */) noexcept {
  1136. return dynamic_extent;
  1137. }
  1138.  
  1139. /// Returns the N-th Extent.
  1140. constexpr std::ptrdiff_t extent(size_t n) const noexcept {
  1141. return m_dynamic_extents[n];
  1142. }
  1143.  
  1144. private:
  1145. std::array<std::ptrdiff_t, Rank> m_dynamic_extents{};
  1146. };
  1147.  
  1148. template <std::size_t Rank, std::size_t RankDynamic,
  1149. std::ptrdiff_t... StaticExtents>
  1150. class ExtentsStorage_ {
  1151. public:
  1152. // [mdspan.extents.constructors]
  1153.  
  1154. ExtentsStorage_() = default;
  1155.  
  1156. template <typename... IndexType,
  1157. typename = std::enable_if_t<conjunction<
  1158. std::is_convertible<IndexType, std::ptrdiff_t>...>::value>,
  1159. typename = std::enable_if_t<sizeof...(IndexType) == RankDynamic>>
  1160. constexpr explicit ExtentsStorage_(IndexType... extent) noexcept
  1161. : m_dynamic_extents{static_cast<std::ptrdiff_t>(extent)...} {}
  1162.  
  1163. constexpr explicit ExtentsStorage_(
  1164. const std::array<std::ptrdiff_t, RankDynamic>& extents) noexcept
  1165. : m_dynamic_extents{extents} {}
  1166.  
  1167. // [mdspan.extents.obs], Observers of the domain multi-index space
  1168.  
  1169. /// Returns sizeof...(StaticExtents)
  1170. static constexpr std::size_t rank() noexcept { return Rank; }
  1171.  
  1172. /// Returns sizeof...(StaticExtents)
  1173. static constexpr std::size_t rank_dynamic() noexcept { return RankDynamic; }
  1174.  
  1175. /// Returns dynamic_extent.
  1176. static constexpr std::ptrdiff_t static_extent(std::size_t n) noexcept {
  1177. constexpr std::ptrdiff_t static_extents[Rank]{StaticExtents...};
  1178. return static_extents[n];
  1179. }
  1180.  
  1181. /// Returns the N-th Extent.
  1182. constexpr std::ptrdiff_t extent(size_t n) const noexcept {
  1183. constexpr std::ptrdiff_t static_extents[Rank]{StaticExtents...};
  1184. if (static_extents[n] != dynamic_extent) {
  1185. return static_extents[n];
  1186. }
  1187. return m_dynamic_extents[find_dynamic_extent_index(n)];
  1188. }
  1189.  
  1190. private:
  1191. std::array<std::ptrdiff_t, RankDynamic> m_dynamic_extents{};
  1192.  
  1193. static constexpr std::size_t
  1194. find_dynamic_extent_index(std::size_t n) noexcept {
  1195. constexpr std::ptrdiff_t static_extents[Rank]{StaticExtents...};
  1196. std::size_t dynamic_extent_index = 0;
  1197. for (std::size_t dim = 0; dim < n; ++dim) {
  1198. if (static_extents[dim] == dynamic_extent) {
  1199. ++dynamic_extent_index;
  1200. }
  1201. }
  1202. return dynamic_extent_index;
  1203. }
  1204. };
  1205.  
  1206. template <typename... IndexType>
  1207. constexpr std::size_t count_dynamic_extents(IndexType... extent) noexcept {
  1208. constexpr std::size_t Rank = sizeof...(IndexType);
  1209. std::ptrdiff_t extents[Rank]{static_cast<std::ptrdiff_t>(extent)...};
  1210. std::size_t counter = 0;
  1211. for (std::size_t dim = 0; dim < Rank; ++dim) {
  1212. if (extents[dim] == dynamic_extent) {
  1213. ++counter;
  1214. }
  1215. }
  1216. return counter;
  1217. }
  1218.  
  1219. /// An extents object defines a multidimensional index space which is the
  1220. /// Cartesian product of integers extents `[0..N0) * [0..N1) * ...`
  1221. template <std::ptrdiff_t... StaticExtents>
  1222. class extents : private ExtentsStorage_<sizeof...(StaticExtents),
  1223. count_dynamic_extents(StaticExtents...),
  1224. StaticExtents...> {
  1225. private:
  1226. using base_type = ExtentsStorage_<sizeof...(StaticExtents),
  1227. count_dynamic_extents(StaticExtents...),
  1228. StaticExtents...>;
  1229.  
  1230. public:
  1231. // Type Definitions
  1232.  
  1233. using index_type = std::ptrdiff_t;
  1234.  
  1235. // [mdspan.extents.constructors]
  1236.  
  1237. using base_type::base_type;
  1238.  
  1239. // [mdspan.extents.static_observers]
  1240.  
  1241. /// Returns sizeof...(StaticExtents)
  1242. static constexpr std::size_t rank() noexcept { return base_type::rank(); }
  1243.  
  1244. /// Returns sizeof...(StaticExtents)
  1245. static constexpr std::size_t rank_dynamic() noexcept {
  1246. return base_type::rank_dynamic();
  1247. }
  1248.  
  1249. /// Returns the `n`-th `StaticExtent`.
  1250. static constexpr std::ptrdiff_t static_extent(std::size_t n) noexcept {
  1251. return base_type::static_extent(n);
  1252. }
  1253.  
  1254. // [mdspan.extents.observers]
  1255.  
  1256. /// Returns the `n`-th run-time extent.
  1257. constexpr std::ptrdiff_t extent(size_t n) const noexcept {
  1258. return base_type::extent(n);
  1259. }
  1260. };
  1261.  
  1262. // [mdspan.extents.traits.is_extent]
  1263.  
  1264. /// \ingroup type-traits
  1265. /// This is true `std::true_type` iff `E` is `extents<Es...>`
  1266. /// for some `std::ptrdiff_t... Es`.
  1267. /// @{
  1268. template <typename E> struct is_extents : std::false_type {};
  1269. template <std::ptrdiff_t... StaticExtents>
  1270. struct is_extents<extents<StaticExtents...>> : std::true_type {};
  1271. template <typename E> static constexpr bool is_extents_v = is_extents<E>::value;
  1272. /// @}
  1273.  
  1274. /// Returns: `true` if `lhs.rank() == rhs.rank()` and `lhs.extents(r) ==
  1275. /// rhs.extents(r)` for all `r` in the range `[0, lhs.rank())`, or false
  1276. /// otherwise.
  1277. template <std::ptrdiff_t... StaticExtentsL, std::ptrdiff_t... StaticExtentsR>
  1278. constexpr bool operator==(const extents<StaticExtentsL...>& lhs,
  1279. const extents<StaticExtentsR...>& rhs) noexcept {
  1280. if (lhs.rank() != rhs.rank()) {
  1281. return false;
  1282. }
  1283. for (std::size_t r = 0; r < lhs.rank(); ++r) {
  1284. if (lhs.extent(r) != rhs.extent(r)) {
  1285. return false;
  1286. }
  1287. }
  1288. return true;
  1289. }
  1290.  
  1291. template <std::ptrdiff_t... StaticExtentsL, std::ptrdiff_t... StaticExtentsR>
  1292. constexpr bool operator!=(const extents<StaticExtentsL...>& left,
  1293. const extents<StaticExtentsR...>& right) noexcept {
  1294. return !(left == right);
  1295. }
  1296.  
  1297. template <std::ptrdiff_t... StaticExtents>
  1298. constexpr std::ptrdiff_t Size_(const extents<StaticExtents...> e) noexcept {
  1299. const std::size_t rank = e.rank();
  1300. std::ptrdiff_t size = 1;
  1301. for (std::size_t r = 0; r < rank; ++r) {
  1302. size *= e.extent(r);
  1303. }
  1304. return size;
  1305. }
  1306.  
  1307. /// This layout creates mappings which do row first indexing (as in Fortran).
  1308. ///
  1309. /// It holds for all valid `i` and `j` the equation
  1310. /// \code mapping(i + 1, j) - mapping(1, j) == 1 \endcode
  1311. struct layout_left {
  1312.  
  1313. /// This mapping does row first indexing (as in Fortran).
  1314. ///
  1315. /// It holds for all valid `i` and `j` the equation
  1316. /// \code mapping(i + 1, j) - mapping(1, j) == 1 \endcode
  1317. template <typename Extents> class mapping : private Extents {
  1318. public:
  1319. static_assert(is_extents_v<Extents>,
  1320. "Extents must satisfy the extents concept.");
  1321.  
  1322. /// \name Constructors / Destructors
  1323. /// @{
  1324. constexpr mapping() = default;
  1325. constexpr mapping(const mapping&) = default;
  1326. constexpr mapping(mapping&&) = default;
  1327. mapping& operator=(const mapping& other) noexcept = default;
  1328. mapping& operator=(mapping&& other) noexcept = default;
  1329.  
  1330. /// Implicit Conversion from Extents.
  1331. ///
  1332. /// \throws Nothing.
  1333. ///
  1334. /// \post extents() == extents.
  1335. constexpr mapping(const Extents& extents) : Extents{extents} {} // NOLINT
  1336. /// @}
  1337.  
  1338. /// \name Observers
  1339. /// @{
  1340. constexpr const Extents& extents() const noexcept { return *this; }
  1341.  
  1342. constexpr std::ptrdiff_t required_span_size() const noexcept {
  1343. return Size_(extents());
  1344. }
  1345.  
  1346. /// \return Returns the codomain index for specified multi dimensional index
  1347. /// coordinates.
  1348. ///
  1349. /// \effect Equivalent to offset in
  1350. /// \code
  1351. /// index_type offset = 0;
  1352. /// for(size_t k = 0; k < Extents::rank(); ++k) {
  1353. /// offset += i[k] * stride(k);
  1354. /// }
  1355. /// \endcode
  1356. /// \throws Nothing.
  1357. template <
  1358. typename... IndexType,
  1359. typename = std::enable_if_t<conjunction<
  1360. std::is_convertible<IndexType, std::ptrdiff_t>...>::value>,
  1361. typename = std::enable_if_t<(sizeof...(IndexType) == Extents::rank())>>
  1362. constexpr std::ptrdiff_t operator()(IndexType... indices) const noexcept {
  1363. return DoMapping_(make_index_sequence<Extents::rank()>(), indices...);
  1364. }
  1365.  
  1366. /// \return Returns the stride value in a specified dimension r.
  1367. ///
  1368. /// \throws Nothing.
  1369. constexpr std::ptrdiff_t stride(std::size_t r) const noexcept {
  1370. std::ptrdiff_t stride = 1;
  1371. for (std::size_t dim = 0; dim < r; ++dim) {
  1372. stride *= extents().extent(dim);
  1373. }
  1374. return stride;
  1375. }
  1376.  
  1377. static constexpr bool is_always_unique() noexcept { return true; }
  1378. static constexpr bool is_always_contiguous() noexcept { return true; }
  1379. static constexpr bool is_always_strided() noexcept { return true; }
  1380.  
  1381. constexpr bool is_unique() const noexcept { return true; }
  1382. constexpr bool is_contiguous() const noexcept { return true; }
  1383. constexpr bool is_strided() const noexcept { return true; }
  1384.  
  1385. template <class OtherExtents>
  1386. constexpr bool operator==(const mapping<OtherExtents>& other) const
  1387. noexcept {
  1388. return extents() == other.extents();
  1389. }
  1390.  
  1391. template <class OtherExtents>
  1392. constexpr bool operator!=(const mapping<OtherExtents>& other) const
  1393. noexcept {
  1394. return !(*this == other);
  1395. }
  1396. /// @}
  1397.  
  1398. private:
  1399. template <std::size_t... Is, typename... IndexType>
  1400. constexpr std::ptrdiff_t DoMapping_(index_sequence<Is...>,
  1401. IndexType... indices) const noexcept {
  1402. const std::ptrdiff_t is[Extents::rank()]{
  1403. static_cast<std::ptrdiff_t>(indices)...};
  1404. const std::ptrdiff_t strides[Extents::rank()]{stride(Is)...};
  1405. std::ptrdiff_t index = 0;
  1406. for (std::size_t r = 0; r < Extents::rank(); ++r) {
  1407. index += strides[r] * is[r];
  1408. }
  1409. return index;
  1410. }
  1411. };
  1412. };
  1413.  
  1414. struct layout_right {
  1415. template <typename Extents> class mapping : private Extents {
  1416. public:
  1417. constexpr mapping() = default;
  1418. constexpr mapping(const mapping&) = default;
  1419. constexpr mapping(mapping&&) = default;
  1420. mapping& operator=(const mapping&) noexcept = default;
  1421. mapping& operator=(mapping&&) noexcept = default;
  1422.  
  1423. constexpr mapping(const Extents& extents) : Extents{extents} {}
  1424.  
  1425. constexpr const Extents& extents() const noexcept { return *this; }
  1426.  
  1427. constexpr std::ptrdiff_t required_span_size() const noexcept {
  1428. return Size_(extents());
  1429. }
  1430.  
  1431. template <
  1432. typename... IndexType,
  1433. typename = std::enable_if_t<conjunction<
  1434. std::is_convertible<IndexType, std::ptrdiff_t>...>::value>,
  1435. typename = std::enable_if_t<(sizeof...(IndexType) == Extents::rank())>>
  1436. constexpr std::ptrdiff_t operator()(IndexType... indices) const noexcept {
  1437. return DoMapping_(make_index_sequence<Extents::rank()>(), indices...);
  1438. }
  1439.  
  1440. constexpr std::ptrdiff_t stride(std::size_t r) const noexcept {
  1441. std::ptrdiff_t stride = 1;
  1442. for (std::size_t dim = r + 1; dim < Extents::rank(); ++dim) {
  1443. stride *= extents().extent(dim);
  1444. }
  1445. return stride;
  1446. }
  1447.  
  1448. static constexpr bool is_always_unique() noexcept { return true; }
  1449. static constexpr bool is_always_contiguous() noexcept { return true; }
  1450. static constexpr bool is_always_strided() noexcept { return true; }
  1451.  
  1452. constexpr bool is_unique() const noexcept { return true; }
  1453. constexpr bool is_contiguous() const noexcept { return true; }
  1454. constexpr bool is_strided() const noexcept { return true; }
  1455.  
  1456. template <class OtherExtents>
  1457. constexpr bool operator==(const mapping<OtherExtents>& other) const
  1458. noexcept {
  1459. return extents() == other.extents();
  1460. }
  1461.  
  1462. template <class OtherExtents>
  1463. constexpr bool operator!=(const mapping<OtherExtents>& other) const
  1464. noexcept {
  1465. return !(*this == other);
  1466. }
  1467.  
  1468. private:
  1469. template <std::size_t... Is, typename... IndexType>
  1470. constexpr std::ptrdiff_t DoMapping_(index_sequence<Is...>,
  1471. IndexType... indices) const noexcept {
  1472. const std::ptrdiff_t is[Extents::rank()]{
  1473. static_cast<std::ptrdiff_t>(indices)...};
  1474. const std::ptrdiff_t strides[Extents::rank()]{stride(Is)...};
  1475. std::ptrdiff_t index = 0;
  1476. for (std::size_t r = 0; r < Extents::rank(); ++r) {
  1477. index += strides[r] * is[r];
  1478. }
  1479. return index;
  1480. }
  1481. };
  1482. };
  1483.  
  1484. struct layout_stride {
  1485. template <class Extents> class mapping : private Extents {
  1486. public:
  1487. // [mdspan.layout.stride.cons], layout_stride::mapping constructors
  1488. constexpr mapping() = default;
  1489.  
  1490. constexpr mapping(
  1491. const Extents& e,
  1492. const std::array<std::ptrdiff_t, Extents::rank()>& s) noexcept
  1493. : Extents(e), strides_(s) {}
  1494.  
  1495. std::array<std::ptrdiff_t, Extents::rank()>
  1496. MakeStrides(const layout_left::mapping<Extents>& other) {
  1497. std::array<std::ptrdiff_t, Extents::rank()> strides;
  1498. for (std::size_t s = 0; s < Extents::rank(); ++s) {
  1499. strides[s] = other.stride(s);
  1500. }
  1501. return strides;
  1502. }
  1503.  
  1504. constexpr mapping(const layout_left::mapping<Extents>& other)
  1505. : mapping(other.extents(), MakeStrides(other)) {}
  1506.  
  1507. // [mdspan.layout.stride.ops], layout_stride::mapping operations
  1508. constexpr const Extents& extents() const noexcept { return *this; }
  1509.  
  1510. constexpr const std::array<std::ptrdiff_t, Extents::rank()>& strides() const
  1511. noexcept {
  1512. return strides_;
  1513. }
  1514.  
  1515. constexpr std::ptrdiff_t required_span_size() const noexcept {
  1516. std::ptrdiff_t max = extents().extent(0) * strides_[0];
  1517. for (std::size_t r = 1; r < Extents::rank(); ++r) {
  1518. max = std::max(extents().extent(r) * strides_[r], max);
  1519. }
  1520. return max;
  1521. }
  1522.  
  1523. template <
  1524. typename... IndexType,
  1525. typename = std::enable_if_t<conjunction<
  1526. std::is_convertible<IndexType, std::ptrdiff_t>...>::value>,
  1527. typename = std::enable_if_t<(sizeof...(IndexType) == Extents::rank())>>
  1528. std::ptrdiff_t operator()(IndexType... is) const {
  1529. const std::array<std::ptrdiff_t, Extents::rank()> idx{
  1530. static_cast<std::ptrdiff_t>(is)...};
  1531. std::ptrdiff_t offset = 0;
  1532. for (std::size_t r = 0; r < Extents::rank(); ++r) {
  1533. offset += idx[r] * strides_[r];
  1534. }
  1535. return offset;
  1536. }
  1537.  
  1538. static constexpr bool is_always_unique() noexcept { return true; }
  1539. static constexpr bool is_always_contiguous() noexcept { return false; }
  1540. static constexpr bool is_always_strided() noexcept { return true; }
  1541.  
  1542. constexpr bool is_unique() const noexcept { return true; }
  1543. constexpr bool is_contiguous() const noexcept { return false; }
  1544. constexpr bool is_strided() const noexcept { return true; }
  1545.  
  1546. std::ptrdiff_t stride(size_t rank) const noexcept { return strides_[rank]; }
  1547.  
  1548. template <class OtherExtents>
  1549. constexpr bool operator==(const mapping<OtherExtents>& other) const
  1550. noexcept {
  1551. return extents() == other.extents();
  1552. }
  1553. template <class OtherExtents>
  1554. constexpr bool operator!=(const mapping<OtherExtents>& other) const
  1555. noexcept {
  1556. return !(*this == other);
  1557. }
  1558.  
  1559. private:
  1560. std::array<std::ptrdiff_t, Extents::rank()> strides_;
  1561. };
  1562. };
  1563.  
  1564. template <class ElementType> struct accessor_basic {
  1565. using offset_policy = accessor_basic;
  1566. using element_type = ElementType;
  1567. using reference = ElementType&;
  1568. using pointer = ElementType*;
  1569.  
  1570. constexpr pointer offset(pointer p, ptrdiff_t i) const noexcept {
  1571. return p + i;
  1572. }
  1573.  
  1574. constexpr reference access(pointer p, ptrdiff_t i) const noexcept {
  1575. return *offset(p, i);
  1576. }
  1577.  
  1578. constexpr pointer decay(pointer p) const noexcept { return p; }
  1579. };
  1580.  
  1581. template <class ElementType, class Extents, class LayoutPolicy = layout_right,
  1582. class AccessorPolicy = accessor_basic<ElementType>>
  1583. class mdspan : AccessorPolicy, LayoutPolicy::template mapping<Extents> {
  1584. public:
  1585. // Domain and codomain types
  1586. using extents_type = Extents;
  1587. using layout_type = LayoutPolicy;
  1588. using accessor_type = AccessorPolicy;
  1589. using mapping_type = typename layout_type::template mapping<extents_type>;
  1590. using element_type = typename accessor_type::element_type;
  1591. using value_type = std::remove_cv_t<element_type>;
  1592. using index_type = std::ptrdiff_t;
  1593. using difference_type = std::ptrdiff_t;
  1594. using pointer = typename accessor_type::pointer;
  1595. using reference = typename accessor_type::reference;
  1596.  
  1597. // [mdspan.basic.cons], mdspan constructors, assignment, and destructor
  1598. constexpr mdspan() noexcept = default;
  1599. constexpr mdspan(const mdspan&) noexcept = default;
  1600. constexpr mdspan(mdspan&&) noexcept = default;
  1601.  
  1602. template <class... IndexType,
  1603. typename = std::enable_if_t<conjunction<
  1604. std::is_convertible<IndexType, std::ptrdiff_t>...>::value>,
  1605. typename = std::enable_if_t<sizeof...(IndexType) ==
  1606. Extents::rank_dynamic()>>
  1607. explicit constexpr mdspan(pointer p, IndexType... dynamic_extents)
  1608. : mdspan(p, Extents(dynamic_extents...)) {}
  1609.  
  1610. template <class IndexType, std::size_t N>
  1611. explicit constexpr mdspan(
  1612. pointer p, const std::array<IndexType, N>& dynamic_extents)
  1613. : mdspan(p, extents_type{dynamic_extents}) {}
  1614.  
  1615. constexpr mdspan(pointer p, const mapping_type& m)
  1616. : accessor_type(), mapping_type(m), ptr_(p) {}
  1617.  
  1618. constexpr mdspan(pointer p, const mapping_type& m,
  1619. const accessor_type& a)
  1620. : accessor_type(a), mapping_type(m), ptr_(p) {}
  1621.  
  1622. template <class OtherElementType, class OtherExtents, class OtherLayoutPolicy,
  1623. class OtherAccessorPolicy>
  1624. constexpr mdspan(
  1625. const mdspan<OtherElementType, OtherExtents, OtherLayoutPolicy,
  1626. OtherAccessorPolicy>& other)
  1627. : accessor_type(), mapping_type(other.mapping()), ptr_(other.data()) {}
  1628.  
  1629. ~mdspan() = default;
  1630.  
  1631. constexpr mdspan& operator=(const mdspan&) noexcept = default;
  1632. constexpr mdspan& operator=(mdspan&&) noexcept = default;
  1633.  
  1634. template <class OtherElementType, class OtherExtents, class OtherLayoutPolicy,
  1635. class OtherAccessorPolicy>
  1636. constexpr mdspan& operator=(
  1637. const mdspan<OtherElementType, OtherExtents, OtherLayoutPolicy,
  1638. OtherAccessorPolicy>& other) noexcept {
  1639. static_cast<mapping_type&>(*this) = other.mapping();
  1640. ptr_ = other.data();
  1641. return *this;
  1642. }
  1643.  
  1644. // [mdspan.basic.mapping], mdspan mapping domain multi-index to access
  1645. // codomain element
  1646. constexpr reference operator[](index_type i) const noexcept {
  1647. return this->operator()(i);
  1648. }
  1649.  
  1650. template <class... IndexType>
  1651. constexpr reference operator()(IndexType... indices) const noexcept {
  1652. const accessor_type acc = accessor();
  1653. const mapping_type map = mapping();
  1654. return acc.access(ptr_, map(indices...));
  1655. }
  1656.  
  1657. template <class IndexType, size_t N>
  1658. constexpr reference operator()(const std::array<IndexType, N>& indices) const
  1659. noexcept {
  1660. const accessor_type acc = accessor();
  1661. const mapping_type map = mapping();
  1662. return acc.access(ptr_, std::apply(map, indices));
  1663. }
  1664.  
  1665. // [mdspan.basic.domobs], mdspan observers of the domain
  1666. // multidimensional index space
  1667.  
  1668. static constexpr int rank() noexcept { return Extents::rank(); }
  1669.  
  1670. static constexpr int rank_dynamic() noexcept {
  1671. return Extents::rank_dynamic();
  1672. }
  1673.  
  1674. static constexpr index_type static_extent(std::size_t rank) noexcept {
  1675. return Extents::static_extent(rank);
  1676. }
  1677.  
  1678. constexpr Extents extents() const noexcept { return mapping().extents(); }
  1679.  
  1680. constexpr index_type extent(std::size_t rank) const noexcept {
  1681. return extents().extent(rank);
  1682. }
  1683.  
  1684. constexpr index_type size() const noexcept { return Size_(extents()); }
  1685.  
  1686. constexpr index_type unique_size() const noexcept { return size(); }
  1687.  
  1688. // [mdspan.basic.codomain], mdspan observers of the codomain
  1689. constexpr span<element_type> get_span() const noexcept {
  1690. return {accessor().decay(ptr_), mapping().required_span_size()};
  1691. }
  1692.  
  1693. constexpr pointer data() const noexcept { return ptr_; }
  1694.  
  1695. // [mdspan.basic.obs], mdspan observers of the mapping
  1696. static constexpr bool is_always_unique() noexcept {
  1697. return mapping_type::is_always_unique();
  1698. }
  1699. static constexpr bool is_always_contiguous() noexcept {
  1700. return mapping_type::is_always_contiguous();
  1701. }
  1702. static constexpr bool is_always_strided() noexcept {
  1703. return mapping_type::is_always_strided();
  1704. }
  1705.  
  1706. constexpr mapping_type mapping() const noexcept { return *this; }
  1707. constexpr accessor_type accessor() const noexcept { return *this; }
  1708. constexpr bool is_unique() const noexcept { return mapping().is_unique(); }
  1709. constexpr bool is_contiguous() const noexcept {
  1710. return mapping().is_contiguous();
  1711. }
  1712. constexpr bool is_strided() const noexcept { return mapping().is_strided(); }
  1713.  
  1714. constexpr index_type stride(std::size_t r) const {
  1715. return mapping().stride(r);
  1716. }
  1717.  
  1718. private:
  1719. pointer ptr_{};
  1720. };
  1721.  
  1722. template <typename T, ptrdiff_t... Extents>
  1723. using static_mdspan = mdspan<T, extents<Extents...>>;
  1724.  
  1725. template <typename T> struct dynamic_extents_;
  1726.  
  1727. template <typename I, I... Is>
  1728. struct dynamic_extents_<integer_sequence<I, Is...>> {
  1729. using type = extents<((void)Is, dynamic_extent)...>;
  1730. };
  1731.  
  1732. template <std::size_t Rank>
  1733. using dynamic_extents =
  1734. typename dynamic_extents_<make_index_sequence<Rank>>::type;
  1735.  
  1736. // template <typename T, std::size_t Rank, typename Layout = layout_right>
  1737. // using DynamicMdSpan = mdspan<T, dynamic_extents<Rank>, Layout>;
  1738.  
  1739. template <typename T, std::size_t Rank, typename Layout = layout_left>
  1740. using dynamic_mdspan = mdspan<T, dynamic_extents<Rank>, Layout>;
  1741.  
  1742. template <typename T, typename E, typename A = accessor_basic<T>>
  1743. using strided_mdspan = mdspan<T, E, layout_stride, A>;
  1744.  
  1745. struct all_type {
  1746. explicit all_type() = default;
  1747. };
  1748. static constexpr all_type all = all_type{};
  1749.  
  1750. /// \cond INTERNAL
  1751. template <typename T>
  1752. struct IsSliceRange_
  1753. : disjunction<
  1754. std::is_convertible<T, std::pair<std::ptrdiff_t, std::ptrdiff_t>>,
  1755. std::is_convertible<T, all_type>> {};
  1756.  
  1757. template <typename I, typename... Is> constexpr I Accumulate_(I x0, Is... xi) {
  1758. const I x[] = {x0, xi...};
  1759. constexpr int size = 1 + static_cast<int>(sizeof...(Is));
  1760. I total = I{};
  1761. for (int i = 0; i < size; ++i) {
  1762. total += x[i];
  1763. }
  1764. return total;
  1765. }
  1766.  
  1767. template <typename... SliceSpecifiers>
  1768. static constexpr std::size_t SliceRank_ =
  1769. Accumulate_(static_cast<int>(IsSliceRange_<SliceSpecifiers>::value)...);
  1770. /// \endcond
  1771.  
  1772. // [mdspan.subspan], subspan creation
  1773. template <class ElementType, class Extents, class LayoutPolicy,
  1774. class AccessorPolicy, class... SliceSpecifiers>
  1775. struct mdspan_subspan { // exposition only
  1776. static constexpr std::size_t slice_rank = SliceRank_<SliceSpecifiers...>;
  1777. using extents_t = dynamic_extents<slice_rank>;
  1778. using layout_t = layout_stride;
  1779. using type = mdspan<ElementType, extents_t, layout_t,
  1780. typename AccessorPolicy::offset_policy>;
  1781. };
  1782.  
  1783. template <class ElementType, class Extents, class LayoutPolicy,
  1784. class AccessorPolicy, class... SliceSpecifiers>
  1785. using mdspan_subspan_t = // exposition only
  1786. typename mdspan_subspan<ElementType, Extents, LayoutPolicy, AccessorPolicy,
  1787. SliceSpecifiers...>::type;
  1788.  
  1789. constexpr std::ptrdiff_t
  1790. SliceExtent_(const std::pair<std::ptrdiff_t, std::ptrdiff_t>& p) {
  1791. assert(p.first <= p.second);
  1792. assert(0 <= p.first);
  1793. return p.second - p.first;
  1794. }
  1795.  
  1796. /// \cond INTERNAL
  1797. constexpr std::ptrdiff_t SliceExtent_(all_type) { return dynamic_extent; }
  1798.  
  1799. template <typename T, typename = std::enable_if_t<!IsSliceRange_<T>::value>>
  1800. constexpr std::ptrdiff_t SliceExtent_(T) {
  1801. return 0;
  1802. }
  1803.  
  1804. template <std::size_t Rank, typename Slice>
  1805. constexpr std::array<std::ptrdiff_t, Rank + 1>
  1806. SlicePushBack__(std::true_type, std::array<std::ptrdiff_t, Rank> array,
  1807. Slice slice) {
  1808. std::array<std::ptrdiff_t, Rank + 1> grown{};
  1809. for (std::size_t i = 0; i < Rank; ++i) {
  1810. grown[i] = array[i];
  1811. }
  1812. grown[Rank] = SliceExtent_(slice);
  1813. return grown;
  1814. }
  1815.  
  1816. template <std::size_t Rank, typename Slice>
  1817. constexpr std::array<std::ptrdiff_t, Rank>
  1818. SlicePushBack__(std::false_type, std::array<std::ptrdiff_t, Rank> array,
  1819. Slice /* slice */) {
  1820. return array;
  1821. }
  1822.  
  1823. template <std::size_t Rank, typename Slice>
  1824. constexpr auto SlicePushBack_(std::array<std::ptrdiff_t, Rank> array,
  1825. Slice slice) {
  1826. return SlicePushBack__(IsSliceRange_<Slice>(), array, slice);
  1827. }
  1828.  
  1829. template <std::size_t Rank>
  1830. constexpr auto MakeSliceExtents__(std::array<std::ptrdiff_t, Rank> result) {
  1831. return result;
  1832. }
  1833.  
  1834. template <std::size_t Rank, typename Slice, typename... Rest>
  1835. constexpr auto MakeSliceExtents__(std::array<std::ptrdiff_t, Rank> prev,
  1836. Slice slice, Rest... slices) {
  1837. return MakeSliceExtents__(SlicePushBack_(prev, slice), slices...);
  1838. }
  1839.  
  1840. template <typename... Slices>
  1841. constexpr auto MakeSliceExtents_(Slices... slices) {
  1842. return MakeSliceExtents__(std::array<std::ptrdiff_t, 0>{}, slices...);
  1843. }
  1844.  
  1845. template <class ElementType, class Extents, class LayoutPolicy,
  1846. class AccessorPolicy, std::size_t... Is>
  1847. constexpr std::array<std::ptrdiff_t, sizeof...(Is)> MakeStrideArray_(
  1848. const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>& src,
  1849. index_sequence<Is...>) {
  1850. return {src.stride(Is)...};
  1851. }
  1852.  
  1853. template <typename T> struct Type_ {};
  1854.  
  1855. template <std::size_t N, std::size_t... Is>
  1856. constexpr std::array<std::size_t, N> AsStdArray__(const std::size_t (&array)[N],
  1857. index_sequence<Is...>) {
  1858. return {array[Is]...};
  1859. }
  1860.  
  1861. template <std::size_t N>
  1862. constexpr std::array<std::size_t, N>
  1863. AsStdArray_(const std::size_t (&array)[N]) {
  1864. return AsStdArray__(array, make_index_sequence<N>());
  1865. }
  1866.  
  1867. template <typename... Slices>
  1868. constexpr std::array<std::size_t, SliceRank_<Slices...>>
  1869. MakeRangeIndices__(Type_<Slices>... /* slices */) {
  1870. constexpr std::size_t is_range[] = {IsSliceRange_<Slices>::value...};
  1871. std::size_t ranges[SliceRank_<Slices...>]{};
  1872. std::size_t ri = 0;
  1873. for (std::size_t i = 0; i < sizeof...(Slices); ++i) {
  1874. if (is_range[i]) {
  1875. ranges[ri++] = i;
  1876. }
  1877. }
  1878. return AsStdArray_(ranges);
  1879. }
  1880.  
  1881. template <typename... Slices, std::size_t... Is>
  1882. constexpr auto MakeRangeIndices_(index_sequence<Is...>,
  1883. Type_<Slices>... /* slices */) {
  1884. constexpr std::array<std::size_t, SliceRank_<Slices...>> indices{
  1885. MakeRangeIndices__(Type_<Slices>{}...)};
  1886. return index_sequence<indices[Is]...>{};
  1887. }
  1888.  
  1889. template <typename... Slices>
  1890. constexpr auto MakeRangeIndices_(Type_<Slices>... slices) {
  1891. return MakeRangeIndices_(make_index_sequence<SliceRank_<Slices...>>{},
  1892. slices...);
  1893. }
  1894.  
  1895. template <typename... Slices> constexpr auto MakeRangeIndices(Slices...) {
  1896. return MakeRangeIndices_(Type_<Slices>{}...);
  1897. }
  1898.  
  1899. template <class ElementType, class Extents, class LayoutPolicy,
  1900. class AccessorPolicy, typename... Slices>
  1901. constexpr auto MakeSliceArray_(
  1902. const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>& src,
  1903. Slices...) {
  1904. constexpr auto range_indices = MakeRangeIndices_(Type_<Slices>{}...);
  1905. return MakeStrideArray_(src, range_indices);
  1906. }
  1907.  
  1908. constexpr std::ptrdiff_t MakeOrigin__(std::ptrdiff_t n) { return n; }
  1909.  
  1910. constexpr std::ptrdiff_t
  1911. MakeOrigin__(std::pair<std::ptrdiff_t, std::ptrdiff_t> p) {
  1912. return p.first;
  1913. }
  1914.  
  1915. constexpr std::ptrdiff_t MakeOrigin__(all_type /* all */) { return 0; }
  1916.  
  1917. template <typename... Slices>
  1918. constexpr std::array<std::ptrdiff_t, sizeof...(Slices)>
  1919. MakeOrigin_(Slices... slices) {
  1920. return {MakeOrigin__(slices)...};
  1921. }
  1922.  
  1923. template <std::size_t... Is, typename F, std::size_t N>
  1924. constexpr auto Apply_(index_sequence<Is...>, F fn,
  1925. std::array<std::ptrdiff_t, N> indices) {
  1926. return fn(indices[Is]...);
  1927. }
  1928.  
  1929. template <typename F, std::size_t N>
  1930. constexpr auto Apply_(F fn, std::array<std::ptrdiff_t, N> indices) {
  1931. return Apply_(make_index_sequence<N>{}, fn, indices);
  1932. }
  1933.  
  1934. constexpr std::ptrdiff_t MapToLength_(all_type) { return -1; }
  1935.  
  1936. constexpr std::ptrdiff_t
  1937. MapToLength_(const std::pair<std::ptrdiff_t, std::ptrdiff_t>& rng) {
  1938. return rng.second - rng.first;
  1939. }
  1940.  
  1941. template <typename T, typename = std::enable_if_t<!IsSliceRange_<T>()>>
  1942. constexpr std::ptrdiff_t MapToLength_(T) {
  1943. return 0;
  1944. }
  1945.  
  1946. template <typename Extents, typename... SliceSpecifiers>
  1947. constexpr std::array<std::ptrdiff_t, SliceRank_<SliceSpecifiers...>>
  1948. MakeSliceExtents2_(const Extents& e, SliceSpecifiers... slices) {
  1949. const std::array<std::ptrdiff_t, Extents::rank()> length{
  1950. MapToLength_(slices)...};
  1951. std::array<std::ptrdiff_t, Extents::rank()> dyn_length{};
  1952. for (std::size_t i = 0; i < Extents::rank(); ++i) {
  1953. if (length[i] < 0) {
  1954. dyn_length[i] = e.extent(i);
  1955. } else {
  1956. dyn_length[i] = length[i];
  1957. }
  1958. }
  1959. std::array<std::ptrdiff_t, SliceRank_<SliceSpecifiers...>> extents{};
  1960. std::size_t slice = 0;
  1961. for (std::size_t i = 0; i < Extents::rank(); ++i) {
  1962. if (dyn_length[i] > 0) {
  1963. extents[slice] = dyn_length[i];
  1964. slice = slice + 1;
  1965. }
  1966. return extents;
  1967. }
  1968. }
  1969. /// \endcond
  1970.  
  1971. template <class ElementType, class Extents, class LayoutPolicy,
  1972. class AccessorPolicy, class... SliceSpecifiers>
  1973. mdspan_subspan_t<ElementType, Extents, LayoutPolicy, AccessorPolicy,
  1974. SliceSpecifiers...>
  1975. subspan(
  1976. const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>& src,
  1977. SliceSpecifiers... slices) noexcept {
  1978. const std::array<std::ptrdiff_t, Extents::rank()> origin =
  1979. MakeOrigin_(slices...);
  1980. const auto map = src.mapping();
  1981. const auto acc = src.accessor();
  1982. constexpr std::size_t slice_rank = SliceRank_<SliceSpecifiers...>;
  1983. using SliceExtents = dynamic_extents<slice_rank>;
  1984. const SliceExtents extents{MakeSliceExtents2_(src.extents(), slices...)};
  1985. const std::array<std::ptrdiff_t, slice_rank> slice_array =
  1986. MakeSliceArray_(src, slices...);
  1987. const layout_stride::mapping<SliceExtents> slice_mapping(extents,
  1988. slice_array);
  1989. return {acc.offset(src.data(), Apply_(map, origin)), slice_mapping};
  1990. }
  1991.  
  1992. template <typename> struct is_mdspan : std::false_type {};
  1993.  
  1994. template <typename T, typename E, typename L, typename A>
  1995. struct is_mdspan<mdspan<T, E, L, A>> : std::true_type {};
  1996.  
  1997. template <typename T> static constexpr bool is_mdspan_v = is_mdspan<T>::value;
  1998.  
  1999. }
  2000. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement