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_
<typename
std::remove_cv
<T
>::type
>;
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_
<typename
std::remove_cv
<T
>::type
>;
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
>()))>>
77 using remove_pointer_t
= typename
std::remove_pointer
<T
>::type
;
78 } // namespace detail_
80 #define REQUIRES(...) bool rt_=true, typename std::enable_if<rt_ && (__VA_ARGS__),bool>::type = true
81 #define IS_VALID_CONTAINER(C) \
82 !detail_::is_span<C>::value && !detail_::is_std_array<C>::value && \
83 !std::is_array<C>::value && detail_::has_size_and_data<C>::value && \
84 std::is_convertible<detail_::remove_pointer_t<decltype(al::data(std::declval<C&>()))>(*)[],element_type(*)[]>::value
86 template<typename T
, size_t E
>
88 static constexpr size_t dynamic_extent
{static_cast<size_t>(-1)};
91 using element_type
= T
;
92 using value_type
= typename
std::remove_cv
<T
>::type
;
93 using index_type
= size_t;
94 using difference_type
= ptrdiff_t;
97 using const_pointer
= const T
*;
99 using const_reference
= const T
&;
101 using iterator
= pointer
;
102 using const_iterator
= const_pointer
;
103 using reverse_iterator
= std::reverse_iterator
<iterator
>;
104 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
106 static constexpr size_t extent
{E
};
108 template<REQUIRES(extent
==0)>
109 constexpr span() noexcept
{ }
110 constexpr span(pointer ptr
, index_type
/*count*/) : mData
{ptr
} { }
111 constexpr span(pointer first
, pointer
/*last*/) : mData
{first
} { }
112 constexpr span(element_type (&arr
)[E
]) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
113 constexpr span(std::array
<value_type
,E
> &arr
) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
114 template<REQUIRES(std::is_const
<element_type
>::value
)>
115 constexpr span(const std::array
<value_type
,E
> &arr
) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
116 template<typename U
, REQUIRES(IS_VALID_CONTAINER(U
))>
117 constexpr span(U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
118 template<typename U
, REQUIRES(IS_VALID_CONTAINER(const U
))>
119 constexpr span(const U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
120 template<typename U
, REQUIRES(!std::is_same
<element_type
,U
>::value
&& 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 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
{ return const_reverse_iterator
{cend()}; }
143 constexpr const_reverse_iterator
crend() const noexcept
{ return const_reverse_iterator
{cbegin()}; }
146 constexpr span
<element_type
,C
> first() const
148 static_assert(E
>= C
, "New size exceeds original capacity");
149 return span
<element_type
,C
>{mData
, C
};
153 constexpr span
<element_type
,C
> last() const
155 static_assert(E
>= C
, "New size exceeds original capacity");
156 return span
<element_type
,C
>{mData
+(E
-C
), C
};
159 template<size_t O
, size_t C
, size_t RealC
=((C
==dynamic_extent
) ? E
-O
: C
)>
160 constexpr span
<element_type
,RealC
> subspan() const
162 static_assert(E
>= O
, "Offset exceeds extent");
163 static_assert(E
-O
>= RealC
, "New size exceeds original capacity");
164 return span
<element_type
,RealC
>{mData
+O
, RealC
};
167 /* NOTE: Can't declare objects of a specialized template class prior to
168 * defining the specialization. As a result, these methods need to be
171 constexpr span
<element_type
,dynamic_extent
> first(size_t count
) const;
172 constexpr span
<element_type
,dynamic_extent
> last(size_t count
) const;
173 constexpr span
<element_type
,dynamic_extent
> subspan(size_t offset
, size_t count
=dynamic_extent
) const;
176 pointer mData
{nullptr};
180 class span
<T
,static_cast<size_t>(-1)> {
181 static constexpr size_t dynamic_extent
{static_cast<size_t>(-1)};
184 using element_type
= T
;
185 using value_type
= typename
std::remove_cv
<T
>::type
;
186 using index_type
= size_t;
187 using difference_type
= ptrdiff_t;
190 using const_pointer
= const T
*;
191 using reference
= T
&;
192 using const_reference
= const T
&;
194 using iterator
= pointer
;
195 using const_iterator
= const_pointer
;
196 using reverse_iterator
= std::reverse_iterator
<iterator
>;
197 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
199 static constexpr size_t extent
{static_cast<size_t>(-1)};
201 constexpr span() noexcept
= default;
202 constexpr span(pointer ptr
, index_type count
) : mData
{ptr
}, mDataEnd
{ptr
+count
} { }
203 constexpr span(pointer first
, pointer last
) : mData
{first
}, mDataEnd
{last
} { }
205 constexpr span(element_type (&arr
)[N
]) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
207 constexpr span(std::array
<value_type
,N
> &arr
) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
208 template<size_t N
, REQUIRES(std::is_const
<element_type
>::value
)>
209 constexpr span(const std::array
<value_type
,N
> &arr
) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
210 template<typename U
, REQUIRES(IS_VALID_CONTAINER(U
))>
211 constexpr span(U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
212 template<typename U
, REQUIRES(IS_VALID_CONTAINER(const U
))>
213 constexpr span(const U
&cont
) : span
{al::data(cont
), al::size(cont
)} { }
214 template<typename U
, size_t N
, REQUIRES((!std::is_same
<element_type
,U
>::value
|| extent
!= N
) && std::is_convertible
<U(*)[],element_type(*)[]>::value
)>
215 constexpr span(const span
<U
,N
> &span_
) noexcept
: span
{al::data(span_
), al::size(span_
)} { }
216 constexpr span(const span
&) noexcept
= default;
218 span
& operator=(const span
&rhs
) noexcept
= default;
220 constexpr reference
front() const { return *mData
; }
221 constexpr reference
back() const { return *(mDataEnd
-1); }
222 constexpr reference
operator[](index_type idx
) const { return mData
[idx
]; }
223 constexpr pointer
data() const noexcept
{ return mData
; }
225 constexpr index_type
size() const noexcept
{ return static_cast<index_type
>(mDataEnd
-mData
); }
226 constexpr index_type
size_bytes() const noexcept
227 { return static_cast<index_type
>(mDataEnd
-mData
) * sizeof(value_type
); }
228 constexpr bool empty() const noexcept
{ return mData
== mDataEnd
; }
230 constexpr iterator
begin() const noexcept
{ return mData
; }
231 constexpr iterator
end() const noexcept
{ return mDataEnd
; }
232 constexpr const_iterator
cbegin() const noexcept
{ return mData
; }
233 constexpr const_iterator
cend() const noexcept
{ return mDataEnd
; }
235 constexpr reverse_iterator
rbegin() const noexcept
{ return reverse_iterator
{end()}; }
236 constexpr reverse_iterator
rend() const noexcept
{ return reverse_iterator
{begin()}; }
237 constexpr const_reverse_iterator
crbegin() const noexcept
{ return const_reverse_iterator
{cend()}; }
238 constexpr const_reverse_iterator
crend() const noexcept
{ return const_reverse_iterator
{cbegin()}; }
241 constexpr span
<element_type
,C
> first() const
242 { return span
<element_type
,C
>{mData
, C
}; }
244 constexpr span
first(size_t count
) const
245 { return (count
>= size()) ? *this : span
{mData
, mData
+count
}; }
248 constexpr span
<element_type
,C
> last() const
249 { return span
<element_type
,C
>{mDataEnd
-C
, C
}; }
251 constexpr span
last(size_t count
) const
252 { return (count
>= size()) ? *this : span
{mDataEnd
-count
, mDataEnd
}; }
254 template<size_t O
, size_t C
=dynamic_extent
>
255 constexpr span
<element_type
,C
> subspan() const
256 { return span
<element_type
,C
>{mData
+O
, (C
!=dynamic_extent
) ? mData
+C
: mDataEnd
}; }
258 constexpr span
subspan(size_t offset
, size_t count
=dynamic_extent
) const
260 return (offset
> size()) ? span
{} :
261 (count
>= size()-offset
) ? span
{mData
+offset
, mDataEnd
} :
262 span
{mData
+offset
, mData
+offset
+count
};
266 pointer mData
{nullptr};
267 pointer mDataEnd
{nullptr};
270 template<typename T
, size_t E
>
271 constexpr inline auto span
<T
,E
>::first(size_t count
) const -> span
<element_type
,dynamic_extent
>
273 return (count
>= size()) ? span
<element_type
>{mData
, extent
} :
274 span
<element_type
>{mData
, count
};
277 template<typename T
, size_t E
>
278 constexpr inline auto span
<T
,E
>::last(size_t count
) const -> span
<element_type
,dynamic_extent
>
280 return (count
>= size()) ? span
<element_type
>{mData
, extent
} :
281 span
<element_type
>{mData
+extent
-count
, count
};
284 template<typename T
, size_t E
>
285 constexpr inline auto span
<T
,E
>::subspan(size_t offset
, size_t count
) const -> span
<element_type
,dynamic_extent
>
287 return (offset
> size()) ? span
<element_type
>{} :
288 (count
>= size()-offset
) ? span
<element_type
>{mData
+offset
, mData
+extent
} :
289 span
<element_type
>{mData
+offset
, mData
+offset
+count
};
292 #undef IS_VALID_CONTAINER
297 #endif /* AL_SPAN_H */