6 #include <initializer_list>
13 constexpr auto size(T
&cont
) -> decltype(cont
.size())
14 { return cont
.size(); }
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
25 constexpr size_t size(std::initializer_list
<T
> list
) noexcept
26 { return list
.size(); }
30 constexpr auto data(T
&cont
) -> decltype(cont
.data())
31 { return cont
.data(); }
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
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)>
50 template<typename
... Ts
>
51 struct make_void
{ using type
= void; };
52 template<typename
... Ts
>
53 using void_t
= typename make_void
<Ts
...>::type
;
56 struct is_span_
: std::false_type
{ };
57 template<typename T
, size_t E
>
58 struct is_span_
<span
<T
,E
>> : std::true_type
{ };
60 using is_span
= is_span_
<std::remove_cv_t
<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
{ };
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
{ };
72 struct has_size_and_data
<T
,
73 void_t
<decltype(al::size(std::declval
<T
>())), decltype(al::data(std::declval
<T
>()))>>
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
>
85 static constexpr size_t dynamic_extent
{static_cast<size_t>(-1)};
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;
94 using const_pointer
= const 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()}; }
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
};
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
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;
173 pointer mData
{nullptr};
177 class span
<T
,static_cast<size_t>(-1)> {
178 static constexpr size_t dynamic_extent
{static_cast<size_t>(-1)};
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;
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
} { }
202 constexpr span(element_type (&arr
)[N
]) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
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()}; }
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
}; }
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
};
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
294 #endif /* AL_SPAN_H */