Limit convolution processing to the output ambisonic order
[openal-soft.git] / common / alspan.h
blob3c65e2e8fb37289235ceee531c5e7dc1a6e048f3
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_<std::remove_cv_t<T>>;
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_<std::remove_cv_t<T>>;
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, std::enable_if_t<rt_ && (__VA_ARGS__),bool> = true
78 #define IS_VALID_CONTAINER(C) \
79 !detail_::is_span<C>::value && !detail_::is_std_array<C>::value && \
80 !std::is_array<C>::value && detail_::has_size_and_data<C>::value && \
81 std::is_convertible<std::remove_pointer_t<decltype(al::data(std::declval<C&>()))>(*)[],element_type(*)[]>::value
83 template<typename T, size_t E>
84 class span {
85 static constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
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 : span{al::data(arr), al::size(arr)} { }
113 template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
114 constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
115 template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
116 constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
117 template<typename U, REQUIRES(!std::is_same<element_type,U>::value && std::is_convertible<U(*)[],element_type(*)[]>::value)>
118 constexpr span(const span<U,E> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
119 constexpr span(const span&) noexcept = default;
121 span& operator=(const span &rhs) noexcept = default;
123 constexpr reference front() const { return *mData; }
124 constexpr reference back() const { return *(mData+E-1); }
125 constexpr reference operator[](index_type idx) const { return mData[idx]; }
126 constexpr pointer data() const noexcept { return mData; }
128 constexpr index_type size() const noexcept { return E; }
129 constexpr index_type size_bytes() const noexcept { return E * sizeof(value_type); }
130 constexpr bool empty() const noexcept { return E == 0; }
132 constexpr iterator begin() const noexcept { return mData; }
133 constexpr iterator end() const noexcept { return mData+E; }
134 constexpr const_iterator cbegin() const noexcept { return mData; }
135 constexpr const_iterator cend() const noexcept { return mData+E; }
137 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
138 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
139 constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; }
140 constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; }
142 template<size_t C>
143 constexpr span<element_type,C> first() const
145 static_assert(E >= C, "New size exceeds original capacity");
146 return span<element_type,C>{mData, C};
149 template<size_t C>
150 constexpr span<element_type,C> last() const
152 static_assert(E >= C, "New size exceeds original capacity");
153 return span<element_type,C>{mData+(E-C), C};
156 template<size_t O, size_t C, size_t RealC=((C==dynamic_extent) ? E-O : C)>
157 constexpr span<element_type,RealC> subspan() const
159 static_assert(E >= O, "Offset exceeds extent");
160 static_assert(E-O >= RealC, "New size exceeds original capacity");
161 return span<element_type,RealC>{mData+O, RealC};
164 /* NOTE: Can't declare objects of a specialized template class prior to
165 * defining the specialization. As a result, these methods need to be
166 * defined later.
168 constexpr span<element_type,dynamic_extent> first(size_t count) const;
169 constexpr span<element_type,dynamic_extent> last(size_t count) const;
170 constexpr span<element_type,dynamic_extent> subspan(size_t offset, size_t count=dynamic_extent) const;
172 private:
173 pointer mData{nullptr};
176 template<typename T>
177 class span<T,static_cast<size_t>(-1)> {
178 static constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
180 public:
181 using element_type = T;
182 using value_type = std::remove_cv_t<T>;
183 using index_type = size_t;
184 using difference_type = ptrdiff_t;
186 using pointer = T*;
187 using const_pointer = const T*;
188 using reference = T&;
189 using const_reference = const T&;
191 using iterator = pointer;
192 using const_iterator = const_pointer;
193 using reverse_iterator = std::reverse_iterator<iterator>;
194 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
196 static constexpr size_t extent{static_cast<size_t>(-1)};
198 constexpr span() noexcept = default;
199 constexpr span(pointer ptr, index_type count) : mData{ptr}, mDataEnd{ptr+count} { }
200 constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { }
201 template<size_t N>
202 constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { }
203 template<size_t N>
204 constexpr span(std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
205 template<size_t N, REQUIRES(std::is_const<element_type>::value)>
206 constexpr span(const std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
207 template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
208 constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
209 template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
210 constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
211 template<typename U, size_t N, REQUIRES((!std::is_same<element_type,U>::value || extent != N) && std::is_convertible<U(*)[],element_type(*)[]>::value)>
212 constexpr span(const span<U,N> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
213 constexpr span(const span&) noexcept = default;
215 span& operator=(const span &rhs) noexcept = default;
217 constexpr reference front() const { return *mData; }
218 constexpr reference back() const { return *(mDataEnd-1); }
219 constexpr reference operator[](index_type idx) const { return mData[idx]; }
220 constexpr pointer data() const noexcept { return mData; }
222 constexpr index_type size() const noexcept { return static_cast<index_type>(mDataEnd-mData); }
223 constexpr index_type size_bytes() const noexcept
224 { return static_cast<index_type>(mDataEnd-mData) * sizeof(value_type); }
225 constexpr bool empty() const noexcept { return mData == mDataEnd; }
227 constexpr iterator begin() const noexcept { return mData; }
228 constexpr iterator end() const noexcept { return mDataEnd; }
229 constexpr const_iterator cbegin() const noexcept { return mData; }
230 constexpr const_iterator cend() const noexcept { return mDataEnd; }
232 constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
233 constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
234 constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{cend()}; }
235 constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{cbegin()}; }
237 template<size_t C>
238 constexpr span<element_type,C> first() const
239 { return span<element_type,C>{mData, C}; }
241 constexpr span first(size_t count) const
242 { return (count >= size()) ? *this : span{mData, mData+count}; }
244 template<size_t C>
245 constexpr span<element_type,C> last() const
246 { return span<element_type,C>{mDataEnd-C, C}; }
248 constexpr span last(size_t count) const
249 { return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; }
251 template<size_t O, size_t C=dynamic_extent>
252 constexpr span<element_type,C> subspan() const
253 { return span<element_type,C>{mData+O, (C!=dynamic_extent) ? mData+O+C : mDataEnd}; }
255 constexpr span subspan(size_t offset, size_t count=dynamic_extent) const
257 return (offset > size()) ? span{} :
258 (count >= size()-offset) ? span{mData+offset, mDataEnd} :
259 span{mData+offset, mData+offset+count};
262 private:
263 pointer mData{nullptr};
264 pointer mDataEnd{nullptr};
267 template<typename T, size_t E>
268 constexpr inline auto span<T,E>::first(size_t count) const -> span<element_type,dynamic_extent>
270 return (count >= size()) ? span<element_type>{mData, extent} :
271 span<element_type>{mData, count};
274 template<typename T, size_t E>
275 constexpr inline auto span<T,E>::last(size_t count) const -> span<element_type,dynamic_extent>
277 return (count >= size()) ? span<element_type>{mData, extent} :
278 span<element_type>{mData+extent-count, count};
281 template<typename T, size_t E>
282 constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const -> span<element_type,dynamic_extent>
284 return (offset > size()) ? span<element_type>{} :
285 (count >= size()-offset) ? span<element_type>{mData+offset, mData+extent} :
286 span<element_type>{mData+offset, mData+offset+count};
289 #undef IS_VALID_CONTAINER
290 #undef REQUIRES
292 } // namespace al
294 #endif /* AL_SPAN_H */