6 #ifndef KAGOME_COMMON_SIZELIMITEDCONTAINER 7 #define KAGOME_COMMON_SIZELIMITEDCONTAINER 9 #include <fmt/format.h> 13 #include <type_traits> 17 #if __has_builtin(__builtin_expect) 18 #define unlikely(x) __builtin_expect((x), 0) 22 #define unlikely(x) (x) 29 template <
typename... Args>
31 :
std::length_error(
fmt::format(
std::forward<Args>(args)...)) {}
34 template <
typename BaseContainer, std::
size_t MaxSize>
37 using Base = BaseContainer;
38 using Span = gsl::span<typename Base::value_type>;
40 static constexpr
bool size_check_is_enabled =
41 MaxSize < std::numeric_limits<typename Base::size_type>::max();
45 static constexpr
bool is_static_collection =
false;
47 [[nodiscard]]
inline constexpr
typename Base::size_type
max_size() {
55 if constexpr (size_check_is_enabled) {
58 "Destination has limited size by {}; requested size is {}",
68 if constexpr (size_check_is_enabled) {
71 "Destination has limited size by {}; requested size is {}",
76 return Base(size, value);
81 if constexpr (size_check_is_enabled) {
82 if (
unlikely(other.size() > max_size())) {
84 "Destination has limited size by {}; Source size is {}",
94 if constexpr (size_check_is_enabled) {
95 if (
unlikely(other.size() > max_size())) {
97 "Destination has limited size by {}; Source size is {}",
102 return std::move(other);
105 template <
typename Iter,
106 typename = std::enable_if_t<std::is_base_of_v<
107 std::input_iterator_tag,
108 typename std::iterator_traits<Iter>::iterator_category>>>
111 if constexpr (size_check_is_enabled) {
112 const size_t size = std::distance(begin, end);
115 "Container has limited size by {}; Source range size is {}",
120 return Base(std::move(begin), std::move(end));
127 if constexpr (size_check_is_enabled) {
128 if (
unlikely(other.size() > max_size())) {
130 "Destination has limited size by {}; Source size is {}",
135 static_cast<Base &
>(*this) = other;
140 if constexpr (size_check_is_enabled) {
141 if (
unlikely(other.size() > max_size())) {
143 "Destination has limited size by {}; Source size is {}",
148 static_cast<Base &
>(*this) = std::move(other);
153 std::initializer_list<typename Base::value_type> list) {
154 if constexpr (size_check_is_enabled) {
155 if (
unlikely(list.size() > max_size())) {
157 "Destination has limited size by {}; Source size is {}",
162 static_cast<Base &
>(*this) =
163 std::forward<std::initializer_list<typename Base::value_type>>(list);
167 void assign(
typename Base::size_type size,
168 const typename Base::value_type &value) {
169 if constexpr (size_check_is_enabled) {
172 "Destination has limited size by {}; Requested size is {}",
177 return Base::assign(size, value);
180 template <
typename Iter,
181 typename = std::enable_if_t<std::is_base_of_v<
182 std::input_iterator_tag,
183 typename std::iterator_traits<Iter>::iterator_category>>>
185 if constexpr (size_check_is_enabled) {
186 const size_t size = std::distance(begin, end);
189 "Container has limited size by {}; Source range size is {}",
194 return Base::assign(std::move(begin), std::move(end));
197 void assign(std::initializer_list<typename Base::value_type> list) {
198 if constexpr (size_check_is_enabled) {
199 if (
unlikely(list.size() > max_size())) {
201 "Container has limited size by {}; Source range size is {}",
206 return Base::assign(std::move(list));
209 template <
typename... Args>
211 if constexpr (size_check_is_enabled) {
212 if (
unlikely(Base::size() >= max_size())) {
214 "Container has limited size by {}; Size is already {} ",
219 return Base::emplace_back(std::forward<Args>(args)...);
225 bool isIter = std::is_same_v<Iter, typename Base::iterator>,
226 bool isConstIter = std::is_same_v<Iter, typename Base::const_iterator>,
227 typename = std::enable_if_t<isIter or isConstIter>>
228 typename Base::iterator
emplace(Iter pos, Args &&...args) {
229 if constexpr (size_check_is_enabled) {
230 if (
unlikely(Base::size() >= max_size())) {
232 "Container has limited size by {}; Size is already {} ",
237 return Base::emplace(std::move(pos), std::forward<Args>(args)...);
242 bool isIter = std::is_same_v<Iter, typename Base::iterator>,
243 bool isConstIter = std::is_same_v<Iter, typename Base::const_iterator>,
244 typename = std::enable_if_t<isIter or isConstIter>>
246 const typename Base::value_type &value) {
247 if constexpr (size_check_is_enabled) {
248 if (
unlikely(Base::size() >= max_size())) {
250 "Destination has limited size by {}; Size is already {} ",
255 return Base::insert(std::move(pos), value);
260 bool isIter = std::is_same_v<Iter, typename Base::iterator>,
261 bool isConstIter = std::is_same_v<Iter, typename Base::const_iterator>,
262 typename = std::enable_if_t<isIter or isConstIter>>
264 typename Base::size_type size,
265 const typename Base::value_type &value) {
266 if constexpr (size_check_is_enabled) {
267 const auto available = max_size() - Base::size();
270 "Destination has limited size by {}; Requested size is {}",
275 return Base::insert(std::move(pos), size, value);
281 bool isIter = std::is_same_v<OutIt, typename Base::iterator>,
282 bool isConstIter = std::is_same_v<OutIt, typename Base::const_iterator>,
283 typename = std::enable_if_t<isIter or isConstIter>,
284 typename = std::enable_if_t<std::is_base_of_v<
285 std::input_iterator_tag,
286 typename std::iterator_traits<InIt>::iterator_category>>>
287 typename Base::iterator
insert(OutIt pos, InIt begin, InIt end) {
288 if constexpr (size_check_is_enabled) {
289 const size_t size = std::distance(begin, end);
290 const auto available = max_size() - Base::size();
293 "Destination has limited size by {} and current size is {}; " 294 "Source range size is {} and would overflow destination",
300 return Base::insert(std::move(pos), std::move(begin), std::move(end));
305 bool isIter = std::is_same_v<Iter, typename Base::iterator>,
306 bool isConstIter = std::is_same_v<Iter, typename Base::const_iterator>,
307 typename = std::enable_if_t<isIter or isConstIter>>
309 Iter pos, std::initializer_list<typename Base::value_type> &&list) {
310 if constexpr (size_check_is_enabled) {
311 const auto available = max_size() - Base::size();
312 if (
unlikely(available < list.size())) {
314 "Container has limited size by {}; Source range size is {}",
319 return Base::insert(pos, std::move(list));
322 template <
typename V>
324 if constexpr (size_check_is_enabled) {
325 if (
unlikely(Base::size() >= max_size())) {
327 "Container has limited size by {}; Size is already maximum",
331 Base::push_back(std::forward<V>(value));
335 if constexpr (size_check_is_enabled) {
338 "Destination has limited size by {}; Requested size is {}",
343 return Base::reserve(size);
346 void resize(
typename Base::size_type size) {
347 if constexpr (size_check_is_enabled) {
350 "Destination has limited size by {}; Requested size is {}",
355 return Base::resize(size);
358 void resize(
typename Base::size_type size,
359 const typename Base::value_type &value) {
360 if constexpr (size_check_is_enabled) {
363 "Destination has limited size by {}; Requested size is {}",
368 return Base::resize(size, value);
373 Base::cbegin(), Base::cend(), other.cbegin(), other.cend());
378 Base::cbegin(), Base::cend(), other.cbegin(), other.cend());
382 return not(*
this == other);
386 return not(*
this == other);
390 return std::lexicographical_compare(
391 Base::cbegin(), Base::cend(), other.cbegin(), other.cend());
395 return std::lexicographical_compare(
396 Base::cbegin(), Base::cend(), other.cbegin(), other.cend());
400 template <
typename ElementType,
size_t MaxSize,
typename... Args>
408 #endif // KAGOME_COMMON_SIZELIMITEDCONTAINER Base::iterator insert(Iter pos, const typename Base::value_type &value)
void resize(typename Base::size_type size)
SizeLimitedContainer(size_t size)
gsl::span< typename Base::value_type > Span
SizeLimitedContainer(std::initializer_list< typename Base::value_type > list)
SizeLimitedContainer & operator=(std::initializer_list< typename Base::value_type > list)
SizeLimitedContainer & operator=(const Base &other)
bool operator!=(const Base &other) const noexcept
bool operator<(const Span &other) const noexcept
Base::reference & emplace_back(Args &&...args)
void assign(std::initializer_list< typename Base::value_type > list)
bool operator!=(const Span &other) const noexcept
constexpr Base::size_type max_size()
bool operator==(const Span &other) const noexcept
void push_back(V &&value)
void assign(Iter begin, Iter end)
void reserve(typename Base::size_type size)
SizeLimitedContainer(const Base &other)
SizeLimitedContainer(size_t size, const typename Base::value_type &value)
bool operator==(const Base &other) const noexcept
void resize(typename Base::size_type size, const typename Base::value_type &value)
MaxSizeException(Args &&...args)
SizeLimitedContainer & operator=(Base &&other)
SizeLimitedContainer(Base &&other)
Base::iterator insert(Iter pos, typename Base::size_type size, const typename Base::value_type &value)
Base::iterator insert(Iter pos, std::initializer_list< typename Base::value_type > &&list)
SizeLimitedContainer(Iter begin, Iter end)
Base::iterator insert(OutIt pos, InIt begin, InIt end)
bool operator<(const Base &other) const noexcept
Base::iterator emplace(Iter pos, Args &&...args)
void assign(typename Base::size_type size, const typename Base::value_type &value)