libcopp  2.2.0
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 
18 LIBCOPP_COPP_NAMESPACE_BEGIN
19 namespace gsl {
20 using std::data;
21 using std::size;
22 using std::span;
23 } // namespace gsl
24 LIBCOPP_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 
39 LIBCOPP_COPP_NAMESPACE_BEGIN
40 namespace gsl {
41 constexpr size_t dynamic_extent = static_cast<size_t>(-1);
42 
43 template <class TCONTAINER>
44 constexpr inline auto size(TCONTAINER &&container) -> decltype(container.size()) {
45  return container.size();
46 }
47 
48 template <class T, size_t SIZE>
49 constexpr inline size_t size(const T (&)[SIZE]) noexcept {
50  return SIZE;
51 }
52 
53 template <class TCONTAINER>
54 constexpr inline auto data(TCONTAINER &&container) -> decltype(container.data()) {
55  return container.data();
56 }
57 
58 template <class T, size_t SIZE>
59 constexpr inline T *data(T (&array_value)[SIZE]) noexcept {
60  return array_value;
61 }
62 
63 template <class TELEMENT>
64 constexpr inline const TELEMENT *data(std::initializer_list<TELEMENT> l) noexcept {
65  return l.begin();
66 }
67 
68 template <class T, size_t EXTENT = dynamic_extent>
69 class span;
70 
71 namespace detail {
75 template <class T>
76 struct is_specialized_span_convertible : std::false_type {};
77 
78 template <class T, size_t N>
79 struct is_specialized_span_convertible<std::array<T, N> > : std::true_type {};
80 
81 template <class T, size_t N>
82 struct is_specialized_span_convertible<T[N]> : std::true_type {};
83 
84 template <class T, size_t EXTENT>
85 struct is_specialized_span_convertible<span<T, EXTENT> > : std::true_type {};
86 } // namespace detail
87 
98 template <class T, size_t EXTENT>
99 class 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:
175  T *data_;
176 };
177 
178 template <class T>
179 class span<T, dynamic_extent> {
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_;
243  T *data_;
244 };
245 } // namespace gsl
246 LIBCOPP_COPP_NAMESPACE_END
247 #endif
248 
249 LIBCOPP_COPP_NAMESPACE_BEGIN
250 namespace gsl {
251 //
252 // make_span() - Utility functions for creating spans
253 //
254 template <class TELEMENT>
255 constexpr span<TELEMENT> make_span(TELEMENT* ptr, typename span<TELEMENT>::size_type count) {
256  return span<TELEMENT>(ptr, count);
257 }
258 
259 template <class TELEMENT>
260 constexpr span<TELEMENT> make_span(TELEMENT* first, TELEMENT* last) {
261  return span<TELEMENT>(first, last);
262 }
263 
264 template <class TELEMENT, std::size_t N>
265 constexpr span<TELEMENT, N> make_span(TELEMENT (&arr)[N]) noexcept {
266  return span<TELEMENT, N>(arr);
267 }
268 
269 template <class TCONTAINER>
271  using container_type = typename std::decay<TCONTAINER>::type;
273 };
274 
275 template <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
285 LIBCOPP_COPP_NAMESPACE_END
span(const span &) noexcept=default
span(T *first, T *last) noexcept
Definition: span.h:197
bool empty() const noexcept
Definition: span.h:223
T * data() const noexcept
Definition: span.h:225
span(const std::array< T, N > &array) noexcept
Definition: span.h:208
span(std::array< T, N > &array) noexcept
Definition: span.h:205
span(const span< U, N > &other) noexcept
Definition: span.h:219
T * end() const noexcept
Definition: span.h:236
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 & operator[](size_t index) const noexcept
Definition: span.h:229
std::ptrdiff_t difference_type
Definition: span.h:185
span(C &&c) noexcept(noexcept(c.data(), c.size()))
Definition: span.h:216
span(T(&array)[N]) noexcept
Definition: span.h:202
T * begin() const noexcept
Definition: span.h:234
std::reverse_iterator< iterator > reverse_iterator
Definition: span.h:191
Definition: span.h:99
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
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
bool empty() const noexcept
Definition: span.h:159
static constexpr size_t extent
Definition: span.h:101
span() noexcept
Definition: span.h:118
T * data() const noexcept
Definition: span.h:161
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
T * begin() const noexcept
Definition: span.h:170
span(const std::array< T, N > &array) noexcept
Definition: span.h:139
T * end() const noexcept
Definition: span.h:172
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 size(const T(&)[SIZE]) noexcept
Definition: span.h:49
constexpr size_t dynamic_extent
Definition: span.h:41
constexpr const TELEMENT * data(std::initializer_list< TELEMENT > l) noexcept
Definition: span.h:64
constexpr auto size(TCONTAINER &&container) -> decltype(container.size())
Definition: span.h:44
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
Definition: span.h:54
constexpr span< TELEMENT > make_span(TELEMENT *ptr, typename span< TELEMENT >::size_type count)
Definition: span.h:255
std::shared_ptr< cli::cmd_option_value > value_type
Definition: cmd_option.h:50
typename std::decay< TCONTAINER >::type container_type
Definition: span.h:271
typename container_type::value_type type
Definition: span.h:272