Move a couple types to the source they're used in
[openal-soft.git] / common / alspan.h
blob42e3523ee092215462a8f9ad57e7773c3656a2ac
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) -> decltype(cont.size())
14 { return cont.size(); }
16 template<typename T>
17 constexpr auto size(const T &cont) -> 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) -> decltype(cont.data())
31 { return cont.data(); }
33 template<typename T>
34 constexpr auto data(const T &cont) -> 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 template<typename T, size_t E=static_cast<size_t>(-1)>
47 class span;
49 namespace detail_ {
50 template<typename... Ts>
51 struct make_void { using type = void; };
52 template<typename... Ts>
53 using void_t = typename make_void<Ts...>::type;
55 template<typename T>
56 struct is_span_ : std::false_type { };
57 template<typename T, size_t E>
58 struct is_span_<span<T,E>> : std::true_type { };
59 template<typename T>
60 using is_span = is_span_<typename std::remove_cv<T>::type>;
62 template<typename T>
63 struct is_std_array_ : std::false_type { };
64 template<typename T, size_t N>
65 struct is_std_array_<std::array<T,N>> : std::true_type { };
66 template<typename T>
67 using is_std_array = is_std_array_<typename std::remove_cv<T>::type>;
69 template<typename T, typename = void>
70 struct has_size_and_data : std::false_type { };
71 template<typename T>
72 struct has_size_and_data<T,
73 void_t<decltype(al::size(std::declval<T>())), decltype(al::data(std::declval<T>()))>>
74 : std::true_type { };
75 } // namespace detail_
77 #define REQUIRES(...) bool rt_=true, typename std::enable_if<rt_ && (__VA_ARGS__),bool>::type = true
78 #define USABLE_CONTAINER_DATA(...) \
79 std::is_convertible<typename std::remove_pointer<decltype(al::data(std::declval<__VA_ARGS__>()))>::type(*)[],element_type(*)[]>::value
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 USABLE_CONTAINER_DATA(C&)
85 template<typename T, size_t E>
86 class span {
87 static constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
89 public:
90 using element_type = T;
91 using value_type = typename std::remove_cv<T>::type;
92 using index_type = size_t;
93 using difference_type = ptrdiff_t;
95 using pointer = T*;
96 using const_pointer = const T*;
97 using reference = T&;
98 using const_reference = const T&;
100 using iterator = pointer;
101 using const_iterator = const_pointer;
102 using reverse_iterator = std::reverse_iterator<iterator>;
103 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
105 static constexpr size_t extent{E};
107 template<REQUIRES(extent==0)>
108 constexpr span() noexcept { }
109 constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { }
110 constexpr span(pointer first, pointer /*last*/) : mData{first} { }
111 constexpr span(element_type (&arr)[E]) noexcept : span{al::data(arr), al::size(arr)} { }
112 constexpr span(std::array<value_type,E> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
113 template<REQUIRES(std::is_const<element_type>::value)>
114 constexpr span(const std::array<value_type,E> &arr) noexcept : 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 && std::is_convertible<U(*)[],element_type(*)[]>::value)>
120 constexpr span(const span<U,E> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
121 constexpr span(const span&) noexcept = default;
123 span& operator=(const span &rhs) noexcept = default;
125 constexpr reference front() const { return *mData; }
126 constexpr reference back() const { return *(mData+E-1); }
127 constexpr reference operator[](index_type idx) const { return mData[idx]; }
128 constexpr pointer data() const noexcept { return mData; }
130 constexpr index_type size() const noexcept { return E; }
131 constexpr index_type size_bytes() const noexcept { return E * sizeof(value_type); }
132 constexpr bool empty() const noexcept { return E == 0; }
134 constexpr iterator begin() const noexcept { return mData; }
135 constexpr iterator end() const noexcept { return mData+E; }
136 constexpr const_iterator cbegin() const noexcept { return mData; }
137 constexpr const_iterator cend() const noexcept { return mData+E; }
139 constexpr reverse_iterator rbegin() const noexcept { return end(); }
140 constexpr reverse_iterator rend() const noexcept { return begin(); }
141 constexpr const_reverse_iterator crbegin() const noexcept { return cend(); }
142 constexpr const_reverse_iterator crend() const noexcept { return cbegin(); }
144 template<size_t C>
145 constexpr span<element_type,C> first() const
147 static_assert(E >= C, "New size exceeds original capacity");
148 return span<element_type,C>{mData, C};
151 template<size_t C>
152 constexpr span<element_type,C> last() const
154 static_assert(E >= C, "New size exceeds original capacity");
155 return span<element_type,C>{mData+(E-C), C};
158 template<size_t O, size_t C, size_t RealC=((C==dynamic_extent) ? E-O : C)>
159 constexpr span<element_type,RealC> subspan() const
161 static_assert(E >= O, "Offset exceeds extent");
162 static_assert(E-O >= RealC, "New size exceeds original capacity");
163 return span<element_type,RealC>{mData+O, RealC};
166 /* NOTE: Can't declare objects of a specialized template class prior to
167 * defining the specialization. As a result, these methods need to be
168 * defined later.
170 constexpr span<element_type,dynamic_extent> first(size_t count) const;
171 constexpr span<element_type,dynamic_extent> last(size_t count) const;
172 constexpr span<element_type,dynamic_extent> subspan(size_t offset, size_t count=dynamic_extent) const;
174 private:
175 pointer mData{nullptr};
178 template<typename T>
179 class span<T,static_cast<size_t>(-1)> {
180 static constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
182 public:
183 using element_type = T;
184 using value_type = typename std::remove_cv<T>::type;
185 using index_type = size_t;
186 using difference_type = ptrdiff_t;
188 using pointer = T*;
189 using const_pointer = const T*;
190 using reference = T&;
191 using const_reference = const T&;
193 using iterator = pointer;
194 using const_iterator = const_pointer;
195 using reverse_iterator = std::reverse_iterator<iterator>;
196 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
198 static constexpr size_t extent{static_cast<size_t>(-1)};
200 constexpr span() noexcept = default;
201 constexpr span(pointer ptr, index_type count) : mData{ptr}, mDataEnd{ptr+count} { }
202 constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { }
203 template<size_t N>
204 constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { }
205 template<size_t N>
206 constexpr span(std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
207 template<size_t N, REQUIRES(std::is_const<element_type>::value)>
208 constexpr span(const std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
209 template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
210 constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
211 template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
212 constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
213 template<typename U, size_t N, REQUIRES((!std::is_same<element_type,U>::value || extent != N) && std::is_convertible<U(*)[],element_type(*)[]>::value)>
214 constexpr span(const span<U,N> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
215 constexpr span(const span&) noexcept = default;
217 span& operator=(const span &rhs) noexcept = default;
219 constexpr reference front() const { return *mData; }
220 constexpr reference back() const { return *(mDataEnd-1); }
221 constexpr reference operator[](index_type idx) const { return mData[idx]; }
222 constexpr pointer data() const noexcept { return mData; }
224 constexpr index_type size() const noexcept { return static_cast<index_type>(mDataEnd-mData); }
225 constexpr index_type size_bytes() const noexcept
226 { return static_cast<index_type>(mDataEnd-mData) * sizeof(value_type); }
227 constexpr bool empty() const noexcept { return mData == mDataEnd; }
229 constexpr iterator begin() const noexcept { return mData; }
230 constexpr iterator end() const noexcept { return mDataEnd; }
231 constexpr const_iterator cbegin() const noexcept { return mData; }
232 constexpr const_iterator cend() const noexcept { return mDataEnd; }
234 constexpr reverse_iterator rbegin() const noexcept { return end(); }
235 constexpr reverse_iterator rend() const noexcept { return begin(); }
236 constexpr const_reverse_iterator crbegin() const noexcept { return cend(); }
237 constexpr const_reverse_iterator crend() const noexcept { return cbegin(); }
239 template<size_t C>
240 constexpr span<element_type,C> first() const
241 { return span<element_type,C>{mData, C}; }
243 constexpr span first(size_t count) const
244 { return (count >= size()) ? *this : span{mData, mData+count}; }
246 template<size_t C>
247 constexpr span<element_type,C> last() const
248 { return span<element_type,C>{mDataEnd-C, C}; }
250 constexpr span last(size_t count) const
251 { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; }
253 template<size_t O, size_t C=dynamic_extent>
254 constexpr span<element_type,C> subspan() const
255 { return span<element_type,C>{mData+O, (C!=dynamic_extent) ? mData+C : mDataEnd}; }
257 constexpr span subspan(size_t offset, size_t count=dynamic_extent) const
259 return (offset > size()) ? span{} :
260 (count >= size()-offset) ? span{mData+offset, mDataEnd} :
261 span{mData+offset, mData+offset+count};
264 private:
265 pointer mData{nullptr};
266 pointer mDataEnd{nullptr};
269 template<typename T, size_t E>
270 constexpr inline auto span<T,E>::first(size_t count) const -> span<element_type,dynamic_extent>
272 return (count >= size()) ? span<element_type>{mData, extent} :
273 span<element_type>{mData, count};
276 template<typename T, size_t E>
277 constexpr inline auto span<T,E>::last(size_t count) const -> span<element_type,dynamic_extent>
279 return (count >= size()) ? span<element_type>{mData, extent} :
280 span<element_type>{mData+extent-count, count};
283 template<typename T, size_t E>
284 constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const -> span<element_type,dynamic_extent>
286 return (offset > size()) ? span<element_type>{} :
287 (count >= size()-offset) ? span<element_type>{mData+offset, mData+extent} :
288 span<element_type>{mData+offset, mData+offset+count};
291 #undef IS_VALID_CONTAINER
292 #undef USABLE_CONTAINER_DATA
293 #undef REQUIRES
295 } // namespace al
297 #endif /* AL_SPAN_H */