libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
span.h
Go to the documentation of this file.
1// Copyright 2023 owent
2
3#pragma once
4
5#include <libcopp/utils/config/libcopp_build_features.h>
6
7// Try to use either `std::span`
8#if defined(LIBCOPP_MACRO_ENABLE_STD_SPAN) && LIBCOPP_MACRO_ENABLE_STD_SPAN
9
10// clang-format off
11#include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
12// clang-format on
13# include <span>
14// clang-format off
15#include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
16// clang-format on
17
18LIBCOPP_COPP_NAMESPACE_BEGIN
19namespace gsl {
20using std::data;
21using std::size;
22using std::span;
23} // namespace gsl
24LIBCOPP_COPP_NAMESPACE_END
25#else
26// clang-format off
27#include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
28// clang-format on
29# include <assert.h>
30# include <array>
31# include <cstddef>
32# include <initializer_list>
33# include <iterator>
34# include <type_traits>
35// clang-format off
36#include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
37// clang-format on
38
39LIBCOPP_COPP_NAMESPACE_BEGIN
40namespace gsl {
41constexpr size_t dynamic_extent = static_cast<size_t>(-1);
42
43template <class TCONTAINER>
44constexpr inline auto size(TCONTAINER &&container) -> decltype(container.size()) {
45 return container.size();
46}
47
48template <class T, size_t SIZE>
49constexpr inline size_t size(const T (&)[SIZE]) noexcept {
50 return SIZE;
51}
52
53template <class TCONTAINER>
54constexpr inline auto data(TCONTAINER &&container) -> decltype(container.data()) {
55 return container.data();
56}
57
58template <class T, size_t SIZE>
59constexpr inline T *data(T (&array_value)[SIZE]) noexcept {
60 return array_value;
61}
62
63template <class TELEMENT>
64constexpr inline const TELEMENT *data(std::initializer_list<TELEMENT> l) noexcept {
65 return l.begin();
66}
67
68template <class T, size_t EXTENT = dynamic_extent>
69class span;
70
71namespace detail {
75template <class T>
76struct is_specialized_span_convertible : std::false_type {};
77
78template <class T, size_t N>
79struct is_specialized_span_convertible<std::array<T, N> > : std::true_type {};
80
81template <class T, size_t N>
82struct is_specialized_span_convertible<T[N]> : std::true_type {};
83
84template <class T, size_t EXTENT>
85struct is_specialized_span_convertible<span<T, EXTENT> > : std::true_type {};
86} // namespace detail
87
98template <class T, size_t EXTENT>
99class span {
100 public:
101 static constexpr size_t extent = EXTENT;
102 using element_type = T;
103 using value_type = typename std::remove_cv<T>::type;
104 using size_type = std::size_t;
105 using difference_type = std::ptrdiff_t;
106 using pointer = T *;
107 using const_pointer = const T *;
108 using reference = T &;
109 using const_reference = const T &;
110 using iterator = T *;
111 using reverse_iterator = std::reverse_iterator<iterator>;
112
113 // This arcane code is how we make default-construction result in an SFINAE error
114 // with C++11 when EXTENT != 0 as specified by the std::span API.
115 //
116 // See https://stackoverflow.com/a/10309720/4447365
117 template <bool B = EXTENT == 0, typename std::enable_if<B>::type * = nullptr>
118 span() noexcept : data_{nullptr} {}
119
120 span(T *input_data, size_t count) noexcept : data_{input_data} {
121 if (count != EXTENT) {
122 std::terminate();
123 }
124 }
125
126 span(T *first, T *last) noexcept : data_{first} {
127 if (std::distance(first, last) != EXTENT) {
128 std::terminate();
129 }
130 }
131
132 template <size_t N, typename std::enable_if<EXTENT == N>::type * = nullptr>
133 span(T (&array)[N]) noexcept : data_{array} {}
134
135 template <size_t N, typename std::enable_if<EXTENT == N>::type * = nullptr>
136 span(std::array<T, N> &array) noexcept : data_{array.data()} {}
137
138 template <size_t N, typename std::enable_if<EXTENT == N>::type * = nullptr>
139 span(const std::array<T, N> &array) noexcept : data_{array.data()} {}
140
141 template <class C,
142 typename std::enable_if<
143 !detail::is_specialized_span_convertible<typename std::decay<C>::type>::value &&
144 std::is_convertible<typename std::remove_pointer<decltype(std::declval<C>().size())>::type (*)[],
145 T (*)[]>::value &&
146 std::is_convertible<decltype(std::declval<C>().size()), size_t>::value>::type * = nullptr>
147 span(C &&c) noexcept(noexcept(c.data(), c.size())) : data_{c.data()} {
148 if (c.size() != EXTENT) {
149 std::terminate();
150 }
151 }
152
153 template <class U, size_t N,
154 typename std::enable_if<N == EXTENT && std::is_convertible<U (*)[], T (*)[]>::value>::type * = nullptr>
155 span(const span<U, N> &other) noexcept : data_{other.data()} {}
156
157 span(const span &) noexcept = default;
158
159 bool empty() const noexcept { return EXTENT == 0; }
160
161 T *data() const noexcept { return data_; }
162
163 size_t size() const noexcept { return EXTENT; }
164
165 T &operator[](size_t index) const noexcept {
166 assert(index < EXTENT);
167 return data_[index];
168 }
169
170 T *begin() const noexcept { return data_; }
171
172 T *end() const noexcept { return data_ + EXTENT; }
173
174 private:
176};
177
178template <class T>
180 public:
181 static constexpr size_t extent = dynamic_extent;
182 using element_type = T;
183 using value_type = typename std::remove_cv<T>::type;
184 using size_type = std::size_t;
185 using difference_type = std::ptrdiff_t;
186 using pointer = T *;
187 using const_pointer = const T *;
188 using reference = T &;
189 using const_reference = const T &;
190 using iterator = T *;
191 using reverse_iterator = std::reverse_iterator<iterator>;
192
193 span() noexcept : extent_{0}, data_{nullptr} {}
194
195 span(T *input_data, size_t count) noexcept : extent_{count}, data_{input_data} {}
196
197 span(T *first, T *last) noexcept : extent_{static_cast<size_t>(std::distance(first, last))}, data_{first} {
198 assert(first <= last);
199 }
200
201 template <size_t N>
202 span(T (&array)[N]) noexcept : extent_{N}, data_{array} {}
203
204 template <size_t N>
205 span(std::array<T, N> &array) noexcept : extent_{N}, data_{array.data()} {}
206
207 template <size_t N>
208 span(const std::array<T, N> &array) noexcept : extent_{N}, data_{array.data()} {}
209
210 template <class C,
211 typename std::enable_if<
212 !detail::is_specialized_span_convertible<typename std::decay<C>::type>::value &&
213 std::is_convertible<typename std::remove_pointer<decltype(std::declval<C>().data())>::type (*)[],
214 T (*)[]>::value &&
215 std::is_convertible<decltype(std::declval<C>().size()), size_t>::value>::type * = nullptr>
216 span(C &&c) noexcept(noexcept(c.data(), c.size())) : extent_{c.size()}, data_{c.data()} {}
217
218 template <class U, size_t N, typename std::enable_if<std::is_convertible<U (*)[], T (*)[]>::value>::type * = nullptr>
219 span(const span<U, N> &other) noexcept : extent_{other.size()}, data_{other.data()} {}
220
221 span(const span &) noexcept = default;
222
223 bool empty() const noexcept { return extent_ == 0; }
224
225 T *data() const noexcept { return data_; }
226
227 size_t size() const noexcept { return extent_; }
228
229 T &operator[](size_t index) const noexcept {
230 assert(index < extent_);
231 return data_[index];
232 }
233
234 T *begin() const noexcept { return data_; }
235
236 T *end() const noexcept { return data_ + extent_; }
237
238 private:
239 // Note: matches libstdc++'s layout for std::span
240 // See
241 // https://github.com/gcc-mirror/gcc/blob/a60701e05b3878000ff9fdde1aecbc472b9dec5a/libstdc%2B%2B-v3/include/std/span#L402-L403
242 size_t extent_;
244};
245} // namespace gsl
246LIBCOPP_COPP_NAMESPACE_END
247#endif
248
249LIBCOPP_COPP_NAMESPACE_BEGIN
250namespace gsl {
251//
252// make_span() - Utility functions for creating spans
253//
254template <class TELEMENT>
255constexpr span<TELEMENT> make_span(TELEMENT* ptr, typename span<TELEMENT>::size_type count) {
256 return span<TELEMENT>(ptr, count);
257}
258
259template <class TELEMENT>
260constexpr span<TELEMENT> make_span(TELEMENT* first, TELEMENT* last) {
261 return span<TELEMENT>(first, last);
262}
263
264template <class TELEMENT, std::size_t N>
265constexpr span<TELEMENT, N> make_span(TELEMENT (&arr)[N]) noexcept {
266 return span<TELEMENT, N>(arr);
267}
268
269template <class TCONTAINER>
271 using container_type = typename std::decay<TCONTAINER>::type;
272 using type = typename container_type::value_type;
273};
274
275template <class TCONTAINER,
276 typename std::enable_if<
277 !std::is_array<typename std::remove_reference<TCONTAINER>::type>::value &&
278 std::is_pointer<decltype(data(std::declval<TCONTAINER>()))>::value &&
279 std::is_convertible<decltype(size(std::declval<TCONTAINER>())), size_t>::value>::type* = nullptr>
281 return span<typename _make_span_value_type<TCONTAINER>::type>(std::forward<TCONTAINER>(cont));
282}
283
284} // namespace gsl
285LIBCOPP_COPP_NAMESPACE_END
span(const span &) noexcept=default
T * data() const noexcept
Definition span.h:225
span(T *first, T *last) noexcept
Definition span.h:197
bool empty() const noexcept
Definition span.h:223
span(const std::array< T, N > &array) noexcept
Definition span.h:208
T * begin() const noexcept
Definition span.h:234
span(std::array< T, N > &array) noexcept
Definition span.h:205
span(const span< U, N > &other) noexcept
Definition span.h:219
typename std::remove_cv< T >::type value_type
Definition span.h:183
span(T *input_data, size_t count) noexcept
Definition span.h:195
size_t size() const noexcept
Definition span.h:227
T * end() const noexcept
Definition span.h:236
std::ptrdiff_t difference_type
Definition span.h:185
span(C &&c) noexcept(noexcept(c.data(), c.size()))
Definition span.h:216
T & operator[](size_t index) const noexcept
Definition span.h:229
span(T(&array)[N]) noexcept
Definition span.h:202
std::reverse_iterator< iterator > reverse_iterator
Definition span.h:191
size_t size() const noexcept
Definition span.h:163
T * pointer
Definition span.h:106
T * data_
Definition span.h:175
span(T *first, T *last) noexcept
Definition span.h:126
span(C &&c) noexcept(noexcept(c.data(), c.size()))
Definition span.h:147
const T * const_pointer
Definition span.h:107
span(T(&array)[N]) noexcept
Definition span.h:133
const T & const_reference
Definition span.h:109
std::reverse_iterator< iterator > reverse_iterator
Definition span.h:111
T * data() const noexcept
Definition span.h:161
span(const span &) noexcept=default
span(std::array< T, N > &array) noexcept
Definition span.h:136
typename std::remove_cv< T >::type value_type
Definition span.h:103
span(const span< U, N > &other) noexcept
Definition span.h:155
T * end() const noexcept
Definition span.h:172
bool empty() const noexcept
Definition span.h:159
T * begin() const noexcept
Definition span.h:170
static constexpr size_t extent
Definition span.h:101
span() noexcept
Definition span.h:118
T element_type
Definition span.h:102
std::size_t size_type
Definition span.h:104
T * iterator
Definition span.h:110
T & operator[](size_t index) const noexcept
Definition span.h:165
T & reference
Definition span.h:108
span(const std::array< T, N > &array) noexcept
Definition span.h:139
span(T *input_data, size_t count) noexcept
Definition span.h:120
std::ptrdiff_t difference_type
Definition span.h:105
Definition not_null.h:23
constexpr size_t dynamic_extent
Definition span.h:41
constexpr span< TELEMENT > make_span(TELEMENT *ptr, typename span< TELEMENT >::size_type count)
Definition span.h:255
constexpr auto size(TCONTAINER &&container) -> decltype(container.size())
Definition span.h:44
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
Definition span.h:54
STL namespace.
typename std::decay< TCONTAINER >::type container_type
Definition span.h:271
typename container_type::value_type type
Definition span.h:272