master
  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
 14namespace 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
 48namespace 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
 95namespace 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
149namespace 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
203namespace 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
260namespace 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
278namespace 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
310namespace 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> // TODO(boomanaiden154): This is currently a
454                              // non-standard extension to include
455                              // std::dynamic_extent tracked by LWG issue 4275.
456                              // This comment should be deleted or the include
457                              // deleted upon resolution.
458#    include <__fwd/span.h>
459#    include <__mdspan/default_accessor.h>
460#    include <__mdspan/extents.h>
461#    include <__mdspan/layout_left.h>
462#    include <__mdspan/layout_right.h>
463#    include <__mdspan/layout_stride.h>
464#    include <__mdspan/mdspan.h>
465#  endif
466
467#  include <version>
468
469#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
470#    pragma GCC system_header
471#  endif
472#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
473
474#endif // _LIBCPP_MDSPAN