| 1 | // -*- C++ -*- |
| 2 | //===----------------------------------------------------------------------===// |
| 3 | // |
| 4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 5 | // See https://llvm.org/LICENSE.txt for license information. |
| 6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 7 | // |
| 8 | //===---------------------------------------------------------------------===// |
| 9 | |
| 10 | /* |
| 11 | |
| 12 | // Overall mdspan synopsis |
| 13 | |
| 14 | namespace std { |
| 15 | // [mdspan.extents], class template extents |
| 16 | template<class IndexType, size_t... Extents> |
| 17 | class extents; |
| 18 | |
| 19 | // [mdspan.extents.dextents], alias template dextents |
| 20 | template<class IndexType, size_t Rank> |
| 21 | using dextents = see below; |
| 22 | |
| 23 | // [mdspan.extents.dims], alias template dims |
| 24 | template<size_t Rank, class IndexType = size_t> |
| 25 | using dims = see below; // since C++26 |
| 26 | |
| 27 | // [mdspan.layout], layout mapping |
| 28 | struct layout_left; |
| 29 | struct layout_right; |
| 30 | struct layout_stride; |
| 31 | |
| 32 | // [mdspan.accessor.default], class template default_accessor |
| 33 | template<class ElementType> |
| 34 | class default_accessor; |
| 35 | |
| 36 | // [mdspan.accessor.aligned], class template aligned_accessor |
| 37 | template<class ElementType, size_t ByteAlignment> |
| 38 | class aligned_accessor; // since C++26 |
| 39 | |
| 40 | // [mdspan.mdspan], class template mdspan |
| 41 | template<class ElementType, class Extents, class LayoutPolicy = layout_right, |
| 42 | class AccessorPolicy = default_accessor<ElementType>> |
| 43 | class mdspan; |
| 44 | } |
| 45 | |
| 46 | // extents synopsis |
| 47 | |
| 48 | namespace std { |
| 49 | template<class _IndexType, size_t... _Extents> |
| 50 | class extents { |
| 51 | public: |
| 52 | using index_type = _IndexType; |
| 53 | using size_type = make_unsigned_t<index_type>; |
| 54 | using rank_type = size_t; |
| 55 | |
| 56 | // [mdspan.extents.obs], observers of the multidimensional index space |
| 57 | static constexpr rank_type rank() noexcept { return sizeof...(_Extents); } |
| 58 | static constexpr rank_type rank_dynamic() noexcept { return dynamic-index(rank()); } |
| 59 | static constexpr size_t static_extent(rank_type) noexcept; |
| 60 | constexpr index_type extent(rank_type) const noexcept; |
| 61 | |
| 62 | // [mdspan.extents.cons], constructors |
| 63 | constexpr extents() noexcept = default; |
| 64 | |
| 65 | template<class _OtherIndexType, size_t... _OtherExtents> |
| 66 | constexpr explicit(see below) |
| 67 | extents(const extents<_OtherIndexType, _OtherExtents...>&) noexcept; |
| 68 | template<class... _OtherIndexTypes> |
| 69 | constexpr explicit extents(_OtherIndexTypes...) noexcept; |
| 70 | template<class _OtherIndexType, size_t N> |
| 71 | constexpr explicit(N != rank_dynamic()) |
| 72 | extents(span<_OtherIndexType, N>) noexcept; |
| 73 | template<class _OtherIndexType, size_t N> |
| 74 | constexpr explicit(N != rank_dynamic()) |
| 75 | extents(const array<_OtherIndexType, N>&) noexcept; |
| 76 | |
| 77 | // [mdspan.extents.cmp], comparison operators |
| 78 | template<class _OtherIndexType, size_t... _OtherExtents> |
| 79 | friend constexpr bool operator==(const extents&, |
| 80 | const extents<_OtherIndexType, _OtherExtents...>&) noexcept; |
| 81 | |
| 82 | private: |
| 83 | // libcxx note: we do not use an array here, but we need to preserve the as-if behavior |
| 84 | // for example the default constructor must zero initialize dynamic extents |
| 85 | array<index_type, rank_dynamic()> dynamic-extents{}; // exposition only |
| 86 | }; |
| 87 | |
| 88 | template<class... Integrals> |
| 89 | explicit extents(Integrals...) |
| 90 | -> see below; |
| 91 | } |
| 92 | |
| 93 | // layout_left synopsis |
| 94 | |
| 95 | namespace std { |
| 96 | template<class Extents> |
| 97 | class layout_left::mapping { |
| 98 | public: |
| 99 | using extents_type = Extents; |
| 100 | using index_type = typename extents_type::index_type; |
| 101 | using size_type = typename extents_type::size_type; |
| 102 | using rank_type = typename extents_type::rank_type; |
| 103 | using layout_type = layout_left; |
| 104 | |
| 105 | // [mdspan.layout.right.cons], constructors |
| 106 | constexpr mapping() noexcept = default; |
| 107 | constexpr mapping(const mapping&) noexcept = default; |
| 108 | constexpr mapping(const extents_type&) noexcept; |
| 109 | template<class OtherExtents> |
| 110 | constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) |
| 111 | mapping(const mapping<OtherExtents>&) noexcept; |
| 112 | template<class OtherExtents> |
| 113 | constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) |
| 114 | mapping(const layout_right::mapping<OtherExtents>&) noexcept; |
| 115 | template<class OtherExtents> |
| 116 | constexpr explicit(extents_type::rank() > 0) |
| 117 | mapping(const layout_stride::mapping<OtherExtents>&) noexcept; |
| 118 | |
| 119 | constexpr mapping& operator=(const mapping&) noexcept = default; |
| 120 | |
| 121 | // [mdspan.layout.right.obs], observers |
| 122 | constexpr const extents_type& extents() const noexcept { return extents_; } |
| 123 | |
| 124 | constexpr index_type required_span_size() const noexcept; |
| 125 | |
| 126 | template<class... Indices> |
| 127 | constexpr index_type operator()(Indices...) const noexcept; |
| 128 | |
| 129 | static constexpr bool is_always_unique() noexcept { return true; } |
| 130 | static constexpr bool is_always_exhaustive() noexcept { return true; } |
| 131 | static constexpr bool is_always_strided() noexcept { return true; } |
| 132 | |
| 133 | static constexpr bool is_unique() noexcept { return true; } |
| 134 | static constexpr bool is_exhaustive() noexcept { return true; } |
| 135 | static constexpr bool is_strided() noexcept { return true; } |
| 136 | |
| 137 | constexpr index_type stride(rank_type) const noexcept; |
| 138 | |
| 139 | template<class OtherExtents> |
| 140 | friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept; |
| 141 | |
| 142 | private: |
| 143 | extents_type extents_{}; // exposition only |
| 144 | }; |
| 145 | } |
| 146 | |
| 147 | // layout_right synopsis |
| 148 | |
| 149 | namespace std { |
| 150 | template<class Extents> |
| 151 | class layout_right::mapping { |
| 152 | public: |
| 153 | using extents_type = Extents; |
| 154 | using index_type = typename extents_type::index_type; |
| 155 | using size_type = typename extents_type::size_type; |
| 156 | using rank_type = typename extents_type::rank_type; |
| 157 | using layout_type = layout_right; |
| 158 | |
| 159 | // [mdspan.layout.right.cons], constructors |
| 160 | constexpr mapping() noexcept = default; |
| 161 | constexpr mapping(const mapping&) noexcept = default; |
| 162 | constexpr mapping(const extents_type&) noexcept; |
| 163 | template<class OtherExtents> |
| 164 | constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) |
| 165 | mapping(const mapping<OtherExtents>&) noexcept; |
| 166 | template<class OtherExtents> |
| 167 | constexpr explicit(!is_convertible_v<OtherExtents, extents_type>) |
| 168 | mapping(const layout_left::mapping<OtherExtents>&) noexcept; |
| 169 | template<class OtherExtents> |
| 170 | constexpr explicit(extents_type::rank() > 0) |
| 171 | mapping(const layout_stride::mapping<OtherExtents>&) noexcept; |
| 172 | |
| 173 | constexpr mapping& operator=(const mapping&) noexcept = default; |
| 174 | |
| 175 | // [mdspan.layout.right.obs], observers |
| 176 | constexpr const extents_type& extents() const noexcept { return extents_; } |
| 177 | |
| 178 | constexpr index_type required_span_size() const noexcept; |
| 179 | |
| 180 | template<class... Indices> |
| 181 | constexpr index_type operator()(Indices...) const noexcept; |
| 182 | |
| 183 | static constexpr bool is_always_unique() noexcept { return true; } |
| 184 | static constexpr bool is_always_exhaustive() noexcept { return true; } |
| 185 | static constexpr bool is_always_strided() noexcept { return true; } |
| 186 | |
| 187 | static constexpr bool is_unique() noexcept { return true; } |
| 188 | static constexpr bool is_exhaustive() noexcept { return true; } |
| 189 | static constexpr bool is_strided() noexcept { return true; } |
| 190 | |
| 191 | constexpr index_type stride(rank_type) const noexcept; |
| 192 | |
| 193 | template<class OtherExtents> |
| 194 | friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept; |
| 195 | |
| 196 | private: |
| 197 | extents_type extents_{}; // exposition only |
| 198 | }; |
| 199 | } |
| 200 | |
| 201 | // layout_stride synopsis |
| 202 | |
| 203 | namespace std { |
| 204 | template<class Extents> |
| 205 | class layout_stride::mapping { |
| 206 | public: |
| 207 | using extents_type = Extents; |
| 208 | using index_type = typename extents_type::index_type; |
| 209 | using size_type = typename extents_type::size_type; |
| 210 | using rank_type = typename extents_type::rank_type; |
| 211 | using layout_type = layout_stride; |
| 212 | |
| 213 | private: |
| 214 | static constexpr rank_type rank_ = extents_type::rank(); // exposition only |
| 215 | |
| 216 | public: |
| 217 | // [mdspan.layout.stride.cons], constructors |
| 218 | constexpr mapping() noexcept; |
| 219 | constexpr mapping(const mapping&) noexcept = default; |
| 220 | template<class OtherIndexType> |
| 221 | constexpr mapping(const extents_type&, span<OtherIndexType, rank_>) noexcept; |
| 222 | template<class OtherIndexType> |
| 223 | constexpr mapping(const extents_type&, const array<OtherIndexType, rank_>&) noexcept; |
| 224 | |
| 225 | template<class StridedLayoutMapping> |
| 226 | constexpr explicit(see below) mapping(const StridedLayoutMapping&) noexcept; |
| 227 | |
| 228 | constexpr mapping& operator=(const mapping&) noexcept = default; |
| 229 | |
| 230 | // [mdspan.layout.stride.obs], observers |
| 231 | constexpr const extents_type& extents() const noexcept { return extents_; } |
| 232 | constexpr array<index_type, rank_> strides() const noexcept { return strides_; } |
| 233 | |
| 234 | constexpr index_type required_span_size() const noexcept; |
| 235 | |
| 236 | template<class... Indices> |
| 237 | constexpr index_type operator()(Indices...) const noexcept; |
| 238 | |
| 239 | static constexpr bool is_always_unique() noexcept { return true; } |
| 240 | static constexpr bool is_always_exhaustive() noexcept { return false; } |
| 241 | static constexpr bool is_always_strided() noexcept { return true; } |
| 242 | |
| 243 | static constexpr bool is_unique() noexcept { return true; } |
| 244 | constexpr bool is_exhaustive() const noexcept; |
| 245 | static constexpr bool is_strided() noexcept { return true; } |
| 246 | |
| 247 | constexpr index_type stride(rank_type i) const noexcept { return strides_[i]; } |
| 248 | |
| 249 | template<class OtherMapping> |
| 250 | friend constexpr bool operator==(const mapping&, const OtherMapping&) noexcept; |
| 251 | |
| 252 | private: |
| 253 | extents_type extents_{}; // exposition only |
| 254 | array<index_type, rank_> strides_{}; // exposition only |
| 255 | }; |
| 256 | } |
| 257 | |
| 258 | // default_accessor synopsis |
| 259 | |
| 260 | namespace std { |
| 261 | template<class ElementType> |
| 262 | struct default_accessor { |
| 263 | using offset_policy = default_accessor; |
| 264 | using element_type = ElementType; |
| 265 | using reference = ElementType&; |
| 266 | using data_handle_type = ElementType*; |
| 267 | |
| 268 | constexpr default_accessor() noexcept = default; |
| 269 | template<class OtherElementType> |
| 270 | constexpr default_accessor(default_accessor<OtherElementType>) noexcept; |
| 271 | constexpr reference access(data_handle_type p, size_t i) const noexcept; |
| 272 | constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept; |
| 273 | }; |
| 274 | } |
| 275 | |
| 276 | // aligned_accessor synopsis |
| 277 | |
| 278 | namespace std { |
| 279 | template<class ElementType, size_t ByteAlignment> |
| 280 | struct aligned_accessor { |
| 281 | using offset_policy = default_accessor<ElementType>; |
| 282 | using element_type = ElementType; |
| 283 | using reference = ElementType&; |
| 284 | using data_handle_type = ElementType*; |
| 285 | |
| 286 | static constexpr size_t byte_alignment = ByteAlignment; |
| 287 | |
| 288 | constexpr aligned_accessor() noexcept = default; |
| 289 | |
| 290 | template<class OtherElementType, size_t OtherByteAlignment> |
| 291 | constexpr aligned_accessor( |
| 292 | aligned_accessor<OtherElementType, OtherByteAlignment>) noexcept; |
| 293 | |
| 294 | template<class OtherElementType> |
| 295 | explicit constexpr aligned_accessor( |
| 296 | default_accessor<OtherElementType>) noexcept; |
| 297 | |
| 298 | template<class OtherElementType> |
| 299 | constexpr operator default_accessor<OtherElementType>() const noexcept; |
| 300 | |
| 301 | constexpr reference access(data_handle_type p, size_t i) const noexcept; |
| 302 | |
| 303 | constexpr typename offset_policy::data_handle_type |
| 304 | offset(data_handle_type p, size_t i) const noexcept; |
| 305 | }; |
| 306 | } |
| 307 | |
| 308 | // mdspan synopsis |
| 309 | |
| 310 | namespace std { |
| 311 | template<class ElementType, class Extents, class LayoutPolicy = layout_right, |
| 312 | class AccessorPolicy = default_accessor<ElementType>> |
| 313 | class mdspan { |
| 314 | public: |
| 315 | using extents_type = Extents; |
| 316 | using layout_type = LayoutPolicy; |
| 317 | using accessor_type = AccessorPolicy; |
| 318 | using mapping_type = typename layout_type::template mapping<extents_type>; |
| 319 | using element_type = ElementType; |
| 320 | using value_type = remove_cv_t<element_type>; |
| 321 | using index_type = typename extents_type::index_type; |
| 322 | using size_type = typename extents_type::size_type; |
| 323 | using rank_type = typename extents_type::rank_type; |
| 324 | using data_handle_type = typename accessor_type::data_handle_type; |
| 325 | using reference = typename accessor_type::reference; |
| 326 | |
| 327 | static constexpr rank_type rank() noexcept { return extents_type::rank(); } |
| 328 | static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } |
| 329 | static constexpr size_t static_extent(rank_type r) noexcept |
| 330 | { return extents_type::static_extent(r); } |
| 331 | constexpr index_type extent(rank_type r) const noexcept { return extents().extent(r); } |
| 332 | |
| 333 | // [mdspan.mdspan.cons], constructors |
| 334 | constexpr mdspan(); |
| 335 | constexpr mdspan(const mdspan& rhs) = default; |
| 336 | constexpr mdspan(mdspan&& rhs) = default; |
| 337 | |
| 338 | template<class... OtherIndexTypes> |
| 339 | constexpr explicit mdspan(data_handle_type ptr, OtherIndexTypes... exts); |
| 340 | template<class OtherIndexType, size_t N> |
| 341 | constexpr explicit(N != rank_dynamic()) |
| 342 | mdspan(data_handle_type p, span<OtherIndexType, N> exts); |
| 343 | template<class OtherIndexType, size_t N> |
| 344 | constexpr explicit(N != rank_dynamic()) |
| 345 | mdspan(data_handle_type p, const array<OtherIndexType, N>& exts); |
| 346 | constexpr mdspan(data_handle_type p, const extents_type& ext); |
| 347 | constexpr mdspan(data_handle_type p, const mapping_type& m); |
| 348 | constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a); |
| 349 | |
| 350 | template<class OtherElementType, class OtherExtents, |
| 351 | class OtherLayoutPolicy, class OtherAccessorPolicy> |
| 352 | constexpr explicit(see below) |
| 353 | mdspan(const mdspan<OtherElementType, OtherExtents, |
| 354 | OtherLayoutPolicy, OtherAccessorPolicy>& other); |
| 355 | |
| 356 | constexpr mdspan& operator=(const mdspan& rhs) = default; |
| 357 | constexpr mdspan& operator=(mdspan&& rhs) = default; |
| 358 | |
| 359 | // [mdspan.mdspan.members], members |
| 360 | template<class... OtherIndexTypes> |
| 361 | constexpr reference operator[](OtherIndexTypes... indices) const; |
| 362 | template<class OtherIndexType> |
| 363 | constexpr reference operator[](span<OtherIndexType, rank()> indices) const; |
| 364 | template<class OtherIndexType> |
| 365 | constexpr reference operator[](const array<OtherIndexType, rank()>& indices) const; |
| 366 | |
| 367 | constexpr size_type size() const noexcept; |
| 368 | [[nodiscard]] constexpr bool empty() const noexcept; |
| 369 | |
| 370 | friend constexpr void swap(mdspan& x, mdspan& y) noexcept; |
| 371 | |
| 372 | constexpr const extents_type& extents() const noexcept { return map_.extents(); } |
| 373 | constexpr const data_handle_type& data_handle() const noexcept { return ptr_; } |
| 374 | constexpr const mapping_type& mapping() const noexcept { return map_; } |
| 375 | constexpr const accessor_type& accessor() const noexcept { return acc_; } |
| 376 | |
| 377 | // per LWG-4021 "mdspan::is_always_meow() should be noexcept" |
| 378 | static constexpr bool is_always_unique() noexcept |
| 379 | { return mapping_type::is_always_unique(); } |
| 380 | static constexpr bool is_always_exhaustive() noexcept |
| 381 | { return mapping_type::is_always_exhaustive(); } |
| 382 | static constexpr bool is_always_strided() noexcept |
| 383 | { return mapping_type::is_always_strided(); } |
| 384 | |
| 385 | constexpr bool is_unique() const |
| 386 | { return map_.is_unique(); } |
| 387 | constexpr bool is_exhaustive() const |
| 388 | { return map_.is_exhaustive(); } |
| 389 | constexpr bool is_strided() const |
| 390 | { return map_.is_strided(); } |
| 391 | constexpr index_type stride(rank_type r) const |
| 392 | { return map_.stride(r); } |
| 393 | |
| 394 | private: |
| 395 | accessor_type acc_; // exposition only |
| 396 | mapping_type map_; // exposition only |
| 397 | data_handle_type ptr_; // exposition only |
| 398 | }; |
| 399 | |
| 400 | template<class CArray> |
| 401 | requires(is_array_v<CArray> && rank_v<CArray> == 1) |
| 402 | mdspan(CArray&) |
| 403 | -> mdspan<remove_all_extents_t<CArray>, extents<size_t, extent_v<CArray, 0>>>; |
| 404 | |
| 405 | template<class Pointer> |
| 406 | requires(is_pointer_v<remove_reference_t<Pointer>>) |
| 407 | mdspan(Pointer&&) |
| 408 | -> mdspan<remove_pointer_t<remove_reference_t<Pointer>>, extents<size_t>>; |
| 409 | |
| 410 | template<class ElementType, class... Integrals> |
| 411 | requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) |
| 412 | explicit mdspan(ElementType*, Integrals...) |
| 413 | -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>; // until C++26 |
| 414 | template<class ElementType, class... Integrals> |
| 415 | requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) |
| 416 | explicit mdspan(ElementType*, Integrals...) |
| 417 | -> mdspan<ElementType, extents<size_t, maybe-static-ext<Integrals>...>>; // since C++26 |
| 418 | |
| 419 | template<class ElementType, class OtherIndexType, size_t N> |
| 420 | mdspan(ElementType*, span<OtherIndexType, N>) |
| 421 | -> mdspan<ElementType, dextents<size_t, N>>; |
| 422 | |
| 423 | template<class ElementType, class OtherIndexType, size_t N> |
| 424 | mdspan(ElementType*, const array<OtherIndexType, N>&) |
| 425 | -> mdspan<ElementType, dextents<size_t, N>>; |
| 426 | |
| 427 | template<class ElementType, class IndexType, size_t... ExtentsPack> |
| 428 | mdspan(ElementType*, const extents<IndexType, ExtentsPack...>&) |
| 429 | -> mdspan<ElementType, extents<IndexType, ExtentsPack...>>; |
| 430 | |
| 431 | template<class ElementType, class MappingType> |
| 432 | mdspan(ElementType*, const MappingType&) |
| 433 | -> mdspan<ElementType, typename MappingType::extents_type, |
| 434 | typename MappingType::layout_type>; |
| 435 | |
| 436 | template<class MappingType, class AccessorType> |
| 437 | mdspan(const typename AccessorType::data_handle_type&, const MappingType&, |
| 438 | const AccessorType&) |
| 439 | -> mdspan<typename AccessorType::element_type, typename MappingType::extents_type, |
| 440 | typename MappingType::layout_type, AccessorType>; |
| 441 | } |
| 442 | */ |
| 443 | |
| 444 | #ifndef _LIBCPP_MDSPAN |
| 445 | #define _LIBCPP_MDSPAN |
| 446 | |
| 447 | #if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) |
| 448 | # include <__cxx03/__config> |
| 449 | #else |
| 450 | # include <__config> |
| 451 | |
| 452 | # if _LIBCPP_STD_VER >= 23 |
| 453 | # include <__fwd/mdspan.h> |
| 454 | # include <__fwd/span.h> |
| 455 | # include <__mdspan/default_accessor.h> |
| 456 | # include <__mdspan/extents.h> |
| 457 | # include <__mdspan/layout_left.h> |
| 458 | # include <__mdspan/layout_right.h> |
| 459 | # include <__mdspan/layout_stride.h> |
| 460 | # include <__mdspan/mdspan.h> |
| 461 | # endif |
| 462 | |
| 463 | # include <version> |
| 464 | |
| 465 | # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| 466 | # pragma GCC system_header |
| 467 | # endif |
| 468 | #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) |
| 469 | |
| 470 | #endif // _LIBCPP_MDSPAN |