Fix a typo in the changelog
[openal-soft.git] / common / alspan.h
blobf2c42b165fb6b3a3fae908cabb263518936747a8
1 #ifndef AL_SPAN_H
2 #define AL_SPAN_H
4 #include <array>
5 #include <cstddef>
6 #include <initializer_list>
7 #include <iterator>
8 #include <type_traits>
10 namespace al {
12 template<typename T>
13 constexpr auto size(T &cont) noexcept(noexcept(cont.size())) -> decltype(cont.size())
14 { return cont.size(); }
16 template<typename T>
17 constexpr auto size(const T &cont) noexcept(noexcept(cont.size())) -> decltype(cont.size())
18 { return cont.size(); }
20 template<typename T, size_t N>
21 constexpr size_t size(T (&)[N]) noexcept
22 { return N; }
24 template<typename T>
25 constexpr size_t size(std::initializer_list<T> list) noexcept
26 { return list.size(); }
29 template<typename T>
30 constexpr auto data(T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data())
31 { return cont.data(); }
33 template<typename T>
34 constexpr auto data(const T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data())
35 { return cont.data(); }
37 template<typename T, size_t N>
38 constexpr T* data(T (&arr)[N]) noexcept
39 { return arr; }
41 template<typename T>
42 constexpr const T* data(std::initializer_list<T> list) noexcept
43 { return list.begin(); }
46 constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
48 template<typename T, size_t E=dynamic_extent>
49 class span;
51 namespace detail_ {
52 template<typename... Ts>
53 struct make_void { using type = void; };
54 template<typename... Ts>
55 using void_t = typename make_void<Ts...>::type;
57 template<typename T>
58 struct is_span_ : std::false_type { };
59 template<typename T, size_t E>
60 struct is_span_<span<T,E>> : std::true_type { };
61 template<typename T>
62 using is_span = is_span_<std::remove_cv_t<T>>;
64 template<typename T>
65 struct is_std_array_ : std::false_type { };
66 template<typename T, size_t N>
67 struct is_std_array_<std::array<T,N>> : std::true_type { };
68 template<typename T>
69 using is_std_array = is_std_array_<std::remove_cv_t<T>>;
71 template<typename T, typename = void>
72 struct has_size_and_data : std::false_type { };
73 template<typename T>
74 struct has_size_and_data<T,
75 void_t<decltype(al::size(std::declval<T>())), decltype(al::data(std::declval<T>()))>>
76 : std::true_type { };
77 } // namespace detail_
79 #define REQUIRES(...) bool rt_=true, std::enable_if_t<rt_ && (__VA_ARGS__),bool> = true
80 #define IS_VALID_CONTAINER(C) \
81 !detail_::is_span<C>::value && !detail_::is_std_array<C>::value && \
82 !std::is_array<C>::value && detail_::has_size_and_data<C>::value && \
83 std::is_convertible<std::remove_pointer_t<decltype(al::data(std::declval<C&>()))>(*)[],element_type(*)[]>::value
85 template<typename T, size_t E>
86 class span {
87 public:
88 using element_type = T;
89 using value_type = std::remove_cv_t<T>;
90 using index_type = size_t;
91 using difference_type = ptrdiff_t;
93 using pointer = T*;
94 using const_pointer = const T*;
95 using reference = T&;
96 using const_reference = const T&;
98 using iterator = pointer;
99 using const_iterator = const_pointer;
100 using reverse_iterator = std::reverse_iterator<iterator>;
101 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
103 static constexpr size_t extent{E};
105 template<REQUIRES(extent==0)>
106 constexpr span() noexcept { }
107 constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { }
108 constexpr span(pointer first, pointer /*last*/) : mData{first} { }
109 constexpr span(element_type (&arr)[E]) noexcept : span{al::data(arr), al::size(arr)} { }
110 constexpr span(std::array<value_type,E> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
111 template<REQUIRES(std::is_const<element_type>::value)>
112 constexpr span(const std::array<value_type,E> &arr) noexcept
113 : span{al::data(arr), al::size(arr)}
115 template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
116 constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
117 template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
118 constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
119 template<typename U, REQUIRES(!std::is_same<element_type,U>::value
120 && std::is_convertible<U(*)[],element_type(*)[]>::value)>
121 constexpr span(const span<U,E> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
122 constexpr span(const span&) noexcept = default;
124 constexpr span& operator=(const span &rhs) noexcept = default;
126 constexpr reference front() const { return *mData; }
127 constexpr reference back() const { return *(mData+E-1); }
128 constexpr reference operator[](index_type idx) const { return mData[idx]; }
129 constexpr pointer data() const noexcept { return mData; }
131 constexpr index_type size() const noexcept { return E; }
132 constexpr index_type size_bytes() const noexcept { return E * sizeof(value_type); }
133 constexpr bool empty() const noexcept { return E == 0; }
135 constexpr iterator begin() const noexcept { return mData; }
136 constexpr iterator end() const noexcept { return mData+E; }
137 constexpr const_iterator cbegin() const noexcept { return mData; }
138 constexpr const_iterator cend() const noexcept { return mData+E; }
140 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
141 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
142 constexpr const_reverse_iterator crbegin() const noexcept
143 { return const_reverse_iterator{cend()}; }
144 constexpr const_reverse_iterator crend() const noexcept
145 { return const_reverse_iterator{cbegin()}; }
147 template<size_t C>
148 constexpr span<element_type,C> first() const
150 static_assert(E >= C, "New size exceeds original capacity");
151 return span<element_type,C>{mData, C};
154 template<size_t C>
155 constexpr span<element_type,C> last() const
157 static_assert(E >= C, "New size exceeds original capacity");
158 return span<element_type,C>{mData+(E-C), C};
161 template<size_t O, size_t C>
162 constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
164 static_assert(E >= O, "Offset exceeds extent");
165 static_assert(E-O >= C, "New size exceeds original capacity");
166 return span<element_type,C>{mData+O, C};
169 template<size_t O, size_t C=dynamic_extent>
170 constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,E-O>>
172 static_assert(E >= O, "Offset exceeds extent");
173 return span<element_type,E-O>{mData+O, E-O};
176 /* NOTE: Can't declare objects of a specialized template class prior to
177 * defining the specialization. As a result, these methods need to be
178 * defined later.
180 constexpr span<element_type,dynamic_extent> first(size_t count) const;
181 constexpr span<element_type,dynamic_extent> last(size_t count) const;
182 constexpr span<element_type,dynamic_extent> subspan(size_t offset,
183 size_t count=dynamic_extent) const;
185 private:
186 pointer mData{nullptr};
189 template<typename T>
190 class span<T,dynamic_extent> {
191 public:
192 using element_type = T;
193 using value_type = std::remove_cv_t<T>;
194 using index_type = size_t;
195 using difference_type = ptrdiff_t;
197 using pointer = T*;
198 using const_pointer = const T*;
199 using reference = T&;
200 using const_reference = const T&;
202 using iterator = pointer;
203 using const_iterator = const_pointer;
204 using reverse_iterator = std::reverse_iterator<iterator>;
205 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
207 static constexpr size_t extent{dynamic_extent};
209 constexpr span() noexcept = default;
210 constexpr span(pointer ptr, index_type count) : mData{ptr}, mDataEnd{ptr+count} { }
211 constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { }
212 template<size_t N>
213 constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { }
214 template<size_t N>
215 constexpr span(std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
216 template<size_t N, REQUIRES(std::is_const<element_type>::value)>
217 constexpr span(const std::array<value_type,N> &arr) noexcept
218 : span{al::data(arr), al::size(arr)}
220 template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
221 constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
222 template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
223 constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
224 template<typename U, size_t N, REQUIRES((!std::is_same<element_type,U>::value || extent != N)
225 && std::is_convertible<U(*)[],element_type(*)[]>::value)>
226 constexpr span(const span<U,N> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
227 constexpr span(const span&) noexcept = default;
229 constexpr span& operator=(const span &rhs) noexcept = default;
231 constexpr reference front() const { return *mData; }
232 constexpr reference back() const { return *(mDataEnd-1); }
233 constexpr reference operator[](index_type idx) const { return mData[idx]; }
234 constexpr pointer data() const noexcept { return mData; }
236 constexpr index_type size() const noexcept { return static_cast<index_type>(mDataEnd-mData); }
237 constexpr index_type size_bytes() const noexcept
238 { return static_cast<index_type>(mDataEnd-mData) * sizeof(value_type); }
239 constexpr bool empty() const noexcept { return mData == mDataEnd; }
241 constexpr iterator begin() const noexcept { return mData; }
242 constexpr iterator end() const noexcept { return mDataEnd; }
243 constexpr const_iterator cbegin() const noexcept { return mData; }
244 constexpr const_iterator cend() const noexcept { return mDataEnd; }
246 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
247 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
248 constexpr const_reverse_iterator crbegin() const noexcept
249 { return const_reverse_iterator{cend()}; }
250 constexpr const_reverse_iterator crend() const noexcept
251 { return const_reverse_iterator{cbegin()}; }
253 template<size_t C>
254 constexpr span<element_type,C> first() const
255 { return span<element_type,C>{mData, C}; }
257 constexpr span first(size_t count) const
258 { return (count >= size()) ? *this : span{mData, mData+count}; }
260 template<size_t C>
261 constexpr span<element_type,C> last() const
262 { return span<element_type,C>{mDataEnd-C, C}; }
264 constexpr span last(size_t count) const
265 { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; }
267 template<size_t O, size_t C>
268 constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
269 { return span<element_type,C>{mData+O, C}; }
271 template<size_t O, size_t C=dynamic_extent>
272 constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,C>>
273 { return span<element_type,C>{mData+O, mDataEnd}; }
275 constexpr span subspan(size_t offset, size_t count=dynamic_extent) const
277 return (offset > size()) ? span{} :
278 (count >= size()-offset) ? span{mData+offset, mDataEnd} :
279 span{mData+offset, mData+offset+count};
282 private:
283 pointer mData{nullptr};
284 pointer mDataEnd{nullptr};
287 template<typename T, size_t E>
288 constexpr inline auto span<T,E>::first(size_t count) const -> span<element_type,dynamic_extent>
290 return (count >= size()) ? span<element_type>{mData, extent} :
291 span<element_type>{mData, count};
294 template<typename T, size_t E>
295 constexpr inline auto span<T,E>::last(size_t count) const -> span<element_type,dynamic_extent>
297 return (count >= size()) ? span<element_type>{mData, extent} :
298 span<element_type>{mData+extent-count, count};
301 template<typename T, size_t E>
302 constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const
303 -> span<element_type,dynamic_extent>
305 return (offset > size()) ? span<element_type>{} :
306 (count >= size()-offset) ? span<element_type>{mData+offset, mData+extent} :
307 span<element_type>{mData+offset, mData+offset+count};
310 #undef IS_VALID_CONTAINER
311 #undef REQUIRES
313 } // namespace al
315 #endif /* AL_SPAN_H */