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
>()))>>
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
>
87 static constexpr size_t dynamic_extent
{static_cast<size_t>(-1)};
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;
96 using const_pointer
= const 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(); }
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
};
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
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;
175 pointer mData
{nullptr};
179 class span
<T
,static_cast<size_t>(-1)> {
180 static constexpr size_t dynamic_extent
{static_cast<size_t>(-1)};
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;
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
} { }
204 constexpr span(element_type (&arr
)[N
]) noexcept
: span
{al::data(arr
), al::size(arr
)} { }
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(); }
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
}; }
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
};
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
297 #endif /* AL_SPAN_H */