xref: /freebsd/contrib/llvm-project/libc/src/__support/CPP/span.h (revision bb722a7d0f1642bff6487f943ad0427799a6e5bf)
1*bb722a7dSDimitry Andric //===-- Standalone implementation std::span ---------------------*- C++ -*-===//
2*bb722a7dSDimitry Andric //
3*bb722a7dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*bb722a7dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*bb722a7dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*bb722a7dSDimitry Andric //
7*bb722a7dSDimitry Andric //===----------------------------------------------------------------------===//
8*bb722a7dSDimitry Andric #ifndef LLVM_LIBC_SRC___SUPPORT_CPP_SPAN_H
9*bb722a7dSDimitry Andric #define LLVM_LIBC_SRC___SUPPORT_CPP_SPAN_H
10*bb722a7dSDimitry Andric 
11*bb722a7dSDimitry Andric #include <stddef.h> // For size_t
12*bb722a7dSDimitry Andric 
13*bb722a7dSDimitry Andric #include "array.h" // For array
14*bb722a7dSDimitry Andric #include "limits.h"
15*bb722a7dSDimitry Andric #include "src/__support/macros/config.h"
16*bb722a7dSDimitry Andric #include "type_traits.h" // For remove_cv_t, enable_if_t, is_same_v, is_const_v
17*bb722a7dSDimitry Andric 
18*bb722a7dSDimitry Andric #include "src/__support/macros/attributes.h"
19*bb722a7dSDimitry Andric 
20*bb722a7dSDimitry Andric namespace LIBC_NAMESPACE_DECL {
21*bb722a7dSDimitry Andric namespace cpp {
22*bb722a7dSDimitry Andric 
23*bb722a7dSDimitry Andric // A trimmed down implementation of std::span.
24*bb722a7dSDimitry Andric // Missing features:
25*bb722a7dSDimitry Andric // - No constant size spans (e.g. Span<int, 4>),
26*bb722a7dSDimitry Andric // - Only handle pointer like types, no fancy interators nor object overriding
27*bb722a7dSDimitry Andric //   the & operator,
28*bb722a7dSDimitry Andric // - No implicit type conversion (e.g. Span<B>, initialized with As where A
29*bb722a7dSDimitry Andric //   inherits from B),
30*bb722a7dSDimitry Andric // - No reverse iterators
31*bb722a7dSDimitry Andric template <typename T> class span {
32*bb722a7dSDimitry Andric   template <typename U>
33*bb722a7dSDimitry Andric   LIBC_INLINE_VAR static constexpr bool is_const_view_v =
34*bb722a7dSDimitry Andric       !cpp::is_const_v<U> && cpp::is_const_v<T> &&
35*bb722a7dSDimitry Andric       cpp::is_same_v<U, remove_cv_t<T>>;
36*bb722a7dSDimitry Andric 
37*bb722a7dSDimitry Andric   template <typename U>
38*bb722a7dSDimitry Andric   LIBC_INLINE_VAR static constexpr bool is_compatible_v =
39*bb722a7dSDimitry Andric       cpp::is_same_v<U, T> || is_const_view_v<U>;
40*bb722a7dSDimitry Andric 
41*bb722a7dSDimitry Andric public:
42*bb722a7dSDimitry Andric   using element_type = T;
43*bb722a7dSDimitry Andric   using value_type = remove_cv_t<T>;
44*bb722a7dSDimitry Andric   using size_type = size_t;
45*bb722a7dSDimitry Andric   using difference_type = ptrdiff_t;
46*bb722a7dSDimitry Andric   using pointer = T *;
47*bb722a7dSDimitry Andric   using const_pointer = const T *;
48*bb722a7dSDimitry Andric   using reference = T &;
49*bb722a7dSDimitry Andric   using const_reference = const T &;
50*bb722a7dSDimitry Andric   using iterator = T *;
51*bb722a7dSDimitry Andric 
52*bb722a7dSDimitry Andric   LIBC_INLINE_VAR static constexpr size_type dynamic_extent =
53*bb722a7dSDimitry Andric       cpp::numeric_limits<size_type>::max();
54*bb722a7dSDimitry Andric 
span()55*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span() : span_data(nullptr), span_size(0) {}
56*bb722a7dSDimitry Andric 
57*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span(const span &) = default;
58*bb722a7dSDimitry Andric 
span(pointer first,size_type count)59*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span(pointer first, size_type count)
60*bb722a7dSDimitry Andric       : span_data(first), span_size(count) {}
61*bb722a7dSDimitry Andric 
span(pointer first,pointer end)62*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span(pointer first, pointer end)
63*bb722a7dSDimitry Andric       : span_data(first), span_size(static_cast<size_t>(end - first)) {}
64*bb722a7dSDimitry Andric 
65*bb722a7dSDimitry Andric   template <typename U, size_t N,
66*bb722a7dSDimitry Andric             cpp::enable_if_t<is_compatible_v<U>, bool> = true>
span(U (& arr)[N])67*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span(U (&arr)[N]) : span_data(arr), span_size(N) {}
68*bb722a7dSDimitry Andric 
69*bb722a7dSDimitry Andric   template <typename U, size_t N,
70*bb722a7dSDimitry Andric             cpp::enable_if_t<is_compatible_v<U>, bool> = true>
span(array<U,N> & arr)71*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span(array<U, N> &arr)
72*bb722a7dSDimitry Andric       : span_data(arr.data()), span_size(arr.size()) {}
73*bb722a7dSDimitry Andric 
74*bb722a7dSDimitry Andric   template <typename U, cpp::enable_if_t<is_compatible_v<U>, bool> = true>
span(span<U> & s)75*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span(span<U> &s)
76*bb722a7dSDimitry Andric       : span_data(s.data()), span_size(s.size()) {}
77*bb722a7dSDimitry Andric 
78*bb722a7dSDimitry Andric   template <typename U, cpp::enable_if_t<is_compatible_v<U>, bool> = true>
79*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span &operator=(span<U> &s) {
80*bb722a7dSDimitry Andric     span_data = s.data();
81*bb722a7dSDimitry Andric     span_size = s.size();
82*bb722a7dSDimitry Andric     return *this;
83*bb722a7dSDimitry Andric   }
84*bb722a7dSDimitry Andric 
85*bb722a7dSDimitry Andric   LIBC_INLINE ~span() = default;
86*bb722a7dSDimitry Andric 
87*bb722a7dSDimitry Andric   LIBC_INLINE constexpr reference operator[](size_type index) const {
88*bb722a7dSDimitry Andric     return data()[index];
89*bb722a7dSDimitry Andric   }
90*bb722a7dSDimitry Andric 
begin()91*bb722a7dSDimitry Andric   LIBC_INLINE constexpr iterator begin() const { return data(); }
end()92*bb722a7dSDimitry Andric   LIBC_INLINE constexpr iterator end() const { return data() + size(); }
front()93*bb722a7dSDimitry Andric   LIBC_INLINE constexpr reference front() const { return (*this)[0]; }
back()94*bb722a7dSDimitry Andric   LIBC_INLINE constexpr reference back() const { return (*this)[size() - 1]; }
data()95*bb722a7dSDimitry Andric   LIBC_INLINE constexpr pointer data() const { return span_data; }
size()96*bb722a7dSDimitry Andric   LIBC_INLINE constexpr size_type size() const { return span_size; }
size_bytes()97*bb722a7dSDimitry Andric   LIBC_INLINE constexpr size_type size_bytes() const {
98*bb722a7dSDimitry Andric     return sizeof(T) * size();
99*bb722a7dSDimitry Andric   }
empty()100*bb722a7dSDimitry Andric   LIBC_INLINE constexpr bool empty() const { return size() == 0; }
101*bb722a7dSDimitry Andric 
102*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span<element_type>
103*bb722a7dSDimitry Andric   subspan(size_type offset, size_type count = dynamic_extent) const {
104*bb722a7dSDimitry Andric     return span<element_type>(data() + offset, count_to_size(offset, count));
105*bb722a7dSDimitry Andric   }
106*bb722a7dSDimitry Andric 
first(size_type count)107*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span<element_type> first(size_type count) const {
108*bb722a7dSDimitry Andric     return subspan(0, count);
109*bb722a7dSDimitry Andric   }
110*bb722a7dSDimitry Andric 
last(size_type count)111*bb722a7dSDimitry Andric   LIBC_INLINE constexpr span<element_type> last(size_type count) const {
112*bb722a7dSDimitry Andric     return span<element_type>(data() + (size() - count), count);
113*bb722a7dSDimitry Andric   }
114*bb722a7dSDimitry Andric 
115*bb722a7dSDimitry Andric private:
count_to_size(size_type offset,size_type count)116*bb722a7dSDimitry Andric   LIBC_INLINE constexpr size_type count_to_size(size_type offset,
117*bb722a7dSDimitry Andric                                                 size_type count) const {
118*bb722a7dSDimitry Andric     if (count == dynamic_extent) {
119*bb722a7dSDimitry Andric       return size() - offset;
120*bb722a7dSDimitry Andric     }
121*bb722a7dSDimitry Andric     return count;
122*bb722a7dSDimitry Andric   }
123*bb722a7dSDimitry Andric 
124*bb722a7dSDimitry Andric   T *span_data;
125*bb722a7dSDimitry Andric   size_t span_size;
126*bb722a7dSDimitry Andric };
127*bb722a7dSDimitry Andric 
128*bb722a7dSDimitry Andric } // namespace cpp
129*bb722a7dSDimitry Andric } // namespace LIBC_NAMESPACE_DECL
130*bb722a7dSDimitry Andric 
131*bb722a7dSDimitry Andric #endif // LLVM_LIBC_SRC___SUPPORT_CPP_SPAN_H
132