Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : * An implementation of `small_vector` (a vector with a small
3 : * buffer optimization). I would probably have preferred to
4 : * call this `inline_vector`, but I'll just go with the canonical
5 : * name for now.
6 : *
7 : * Copyright © 2020-2021 Gene Harvey
8 : *
9 : * This software may be modified and distributed under the terms
10 : * of the MIT license. See the LICENSE file for details.
11 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
12 : #ifndef __PLUMED_small_vector_small_vector_h
13 : #define __PLUMED_small_vector_small_vector_h
14 : /** small_vector.hpp
15 : * An implementation of `small_vector` (a vector with a small
16 : * buffer optimization). I would probably have preferred to
17 : * call this `inline_vector`, but I'll just go with the canonical
18 : * name for now.
19 : *
20 : * Copyright © 2020-2021 Gene Harvey
21 : *
22 : * This software may be modified and distributed under the terms
23 : * of the MIT license. See the LICENSE file for details.
24 : * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
25 :
26 : #ifndef PLUMED_GCH_SMALL_VECTOR_HPP
27 : #define PLUMED_GCH_SMALL_VECTOR_HPP
28 :
29 : #ifdef __clang__
30 : # ifndef PLUMED_GCH_CLANG
31 : # define PLUMED_GCH_CLANG
32 : # endif
33 : # if defined (__cplusplus) && __cplusplus >= 201103L
34 : # ifndef PLUMED_GCH_CLANG_11
35 : # define PLUMED_GCH_CLANG_11
36 : # endif
37 : # endif
38 : # if defined (__cplusplus) && __cplusplus >= 201402L
39 : # ifndef PLUMED_GCH_CLANG_14
40 : # define PLUMED_GCH_CLANG_14
41 : # endif
42 : # endif
43 : # if defined (__cplusplus) && __cplusplus >= 201703L
44 : # ifndef PLUMED_GCH_CLANG_17
45 : # define PLUMED_GCH_CLANG_17
46 : # endif
47 : # endif
48 : # if defined (__cplusplus) && __cplusplus >= 202002L
49 : # ifndef PLUMED_GCH_CLANG_20
50 : # define PLUMED_GCH_CLANG_20
51 : # endif
52 : # endif
53 : #endif
54 :
55 : #ifndef PLUMED_GCH_CPP14_CONSTEXPR
56 : # if defined (__cpp_constexpr) && __cpp_constexpr >= 201304L
57 : # define PLUMED_GCH_CPP14_CONSTEXPR constexpr
58 : # ifndef PLUMED_GCH_HAS_CPP14_CONSTEXPR
59 : # define PLUMED_GCH_HAS_CPP14_CONSTEXPR
60 : # endif
61 : # else
62 : # define PLUMED_GCH_CPP14_CONSTEXPR
63 : # endif
64 : #endif
65 :
66 : #ifndef PLUMED_GCH_CPP17_CONSTEXPR
67 : # if defined (__cpp_constexpr) && __cpp_constexpr >= 201603L
68 : # define PLUMED_GCH_CPP17_CONSTEXPR constexpr
69 : # ifndef PLUMED_GCH_HAS_CPP17_CONSTEXPR
70 : # define PLUMED_GCH_HAS_CPP17_CONSTEXPR
71 : # endif
72 : # else
73 : # define PLUMED_GCH_CPP17_CONSTEXPR
74 : # endif
75 : #endif
76 :
77 : #ifndef PLUMED_GCH_CPP20_CONSTEXPR
78 : # if defined (__cpp_constexpr) && __cpp_constexpr >= 201907L
79 : # define PLUMED_GCH_CPP20_CONSTEXPR constexpr
80 : # ifndef PLUMED_GCH_HAS_CPP20_CONSTEXPR
81 : # define PLUMED_GCH_HAS_CPP20_CONSTEXPR
82 : # endif
83 : # else
84 : # define PLUMED_GCH_CPP20_CONSTEXPR
85 : # endif
86 : #endif
87 :
88 : #ifndef PLUMED_GCH_NORETURN
89 : # if defined (__has_cpp_attribute) && __has_cpp_attribute (noreturn) >= 200809L
90 : # define PLUMED_GCH_NORETURN [[noreturn]]
91 : # else
92 : # define PLUMED_GCH_NORETURN
93 : # endif
94 : #endif
95 :
96 : #ifndef PLUMED_GCH_NODISCARD
97 : # if defined (__has_cpp_attribute) && __has_cpp_attribute (nodiscard) >= 201603L
98 : # if ! defined (__clang__) || defined (PLUMED_GCH_CLANG_17)
99 : # define PLUMED_GCH_NODISCARD [[nodiscard]]
100 : # else
101 : # define PLUMED_GCH_NODISCARD
102 : # endif
103 : # else
104 : # define PLUMED_GCH_NODISCARD
105 : # endif
106 : #endif
107 :
108 : #ifndef PLUMED_GCH_INLINE_VARIABLE
109 : # if defined (__cpp_inline_variables) && __cpp_inline_variables >= 201606L
110 : # define PLUMED_GCH_INLINE_VARIABLE inline
111 : # else
112 : # define PLUMED_GCH_INLINE_VARIABLE
113 : # endif
114 : #endif
115 :
116 : #ifndef PLUMED_GCH_EMPTY_BASE
117 : # if defined (_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918L
118 : # define PLUMED_GCH_EMPTY_BASE __declspec (empty_bases)
119 : # else
120 : # define PLUMED_GCH_EMPTY_BASE
121 : # endif
122 : #endif
123 :
124 : #ifndef PLUMED_GCH_IMPLICIT_CONVERSION
125 : # if defined (__cpp_conditional_explicit) && __cpp_conditional_explicit >= 201806L
126 : # define PLUMED_GCH_IMPLICIT_CONVERSION explicit (false)
127 : # else
128 : # define PLUMED_GCH_IMPLICIT_CONVERSION /* implicit */
129 : # endif
130 : #endif
131 :
132 : #if defined (__cpp_variable_templates) && __cpp_variable_templates >= 201304L
133 : # ifndef PLUMED_GCH_VARIABLE_TEMPLATES
134 : # define PLUMED_GCH_VARIABLE_TEMPLATES
135 : # endif
136 : #endif
137 :
138 : #if defined (__cpp_deduction_guides) && __cpp_deduction_guides >= 201703L
139 : # ifndef PLUMED_GCH_CTAD_SUPPORT
140 : # define PLUMED_GCH_CTAD_SUPPORT
141 : # endif
142 : #endif
143 :
144 : #if defined (__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L
145 : # ifndef PLUMED_GCH_CONSTEXPR_IF
146 : # define PLUMED_GCH_CONSTEXPR_IF
147 : # endif
148 : #endif
149 :
150 : #if defined (__cpp_exceptions) && __cpp_exceptions >= 199711L
151 : # ifndef PLUMED_GCH_EXCEPTIONS
152 : # define PLUMED_GCH_EXCEPTIONS
153 : # endif
154 : #endif
155 :
156 : #ifndef PLUMED_GCH_TRY
157 : # ifdef PLUMED_GCH_EXCEPTIONS
158 : # define PLUMED_GCH_TRY try
159 : # else
160 : # ifdef PLUMED_GCH_CONSTEXPR_IF
161 : # define PLUMED_GCH_TRY if constexpr (true)
162 : # else
163 : # define PLUMED_GCH_TRY if (true)
164 : # endif
165 : # endif
166 : #endif
167 :
168 : #ifndef PLUMED_GCH_CATCH
169 : # ifdef PLUMED_GCH_EXCEPTIONS
170 : # define PLUMED_GCH_CATCH(...) catch (__VA_ARGS__)
171 : # else
172 : # ifdef PLUMED_GCH_CONSTEXPR_IF
173 : # define PLUMED_GCH_CATCH(...) else if constexpr (false)
174 : # else
175 : # define PLUMED_GCH_CATCH(...) else if (false)
176 : # endif
177 : # endif
178 : #endif
179 :
180 : #ifndef PLUMED_GCH_THROW
181 : # ifdef PLUMED_GCH_EXCEPTIONS
182 : # define PLUMED_GCH_THROW throw
183 : # else
184 : # define PLUMED_GCH_THROW
185 : # endif
186 : #endif
187 :
188 : #ifndef PLUMED_GCH_CONSTEVAL
189 : # if defined (__cpp_consteval) && __cpp_consteval >= 201811L
190 : # define PLUMED_GCH_CONSTEVAL consteval
191 : # ifndef PLUMED_GCH_HAS_CONSTEVAL
192 : # define PLUMED_GCH_HAS_CONSTEVAL
193 : # endif
194 : # else
195 : # define PLUMED_GCH_CONSTEVAL constexpr
196 : # endif
197 : #endif
198 :
199 : #if defined (__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L
200 : # ifndef PLUMED_GCH_IMPL_THREE_WAY_COMPARISON
201 : # define PLUMED_GCH_IMPL_THREE_WAY_COMPARISON
202 : # endif
203 : #endif
204 :
205 : #if defined (__cpp_concepts) && __cpp_concepts >= 201907L
206 : # ifndef PLUMED_GCH_CONCEPTS
207 : # define PLUMED_GCH_CONCEPTS
208 : # endif
209 : #endif
210 :
211 : #include <algorithm>
212 : #include <cassert>
213 : #include <cstddef>
214 : #include <cstdint>
215 : #include <cstring>
216 : #include <initializer_list>
217 : #include <iterator>
218 : #include <limits>
219 : #include <memory>
220 : #include <new>
221 : #include <type_traits>
222 : #include <utility>
223 :
224 : #ifdef PLUMED_GCH_IMPL_THREE_WAY_COMPARISON
225 : # if defined (__has_include) && __has_include (<compare>)
226 : # include <compare>
227 : # endif
228 : #endif
229 :
230 : #ifdef PLUMED_GCH_CONCEPTS
231 : # if defined (__has_include) && __has_include (<concepts>)
232 : # include <concepts>
233 : # endif
234 : #endif
235 :
236 : #ifdef PLUMED_GCH_STDLIB_INTEROP
237 : # include <array>
238 : # include <valarray>
239 : # include <vector>
240 : #endif
241 :
242 : #ifdef PLUMED_GCH_EXCEPTIONS
243 : # include <stdexcept>
244 : #else
245 : # include <cstdio>
246 : # include <cstdlib>
247 : #endif
248 :
249 : #if defined (__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
250 : # ifndef PLUMED_GCH_LIB_THREE_WAY_COMPARISON
251 : # define PLUMED_GCH_LIB_THREE_WAY_COMPARISON
252 : # endif
253 : #endif
254 :
255 : #if defined (__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L
256 : # if ! defined (PLUMED_GCH_LIB_CONCEPTS) && ! defined (PLUMED_GCH_DISABLE_CONCEPTS)
257 : # define PLUMED_GCH_LIB_CONCEPTS
258 : # endif
259 : #endif
260 :
261 : #if defined (__cpp_lib_is_final) && __cpp_lib_is_final >= 201402L
262 : # ifndef PLUMED_GCH_LIB_IS_FINAL
263 : # define PLUMED_GCH_LIB_IS_FINAL
264 : # endif
265 : #endif
266 :
267 : #if defined (__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L
268 : # ifndef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
269 : # define PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
270 : # endif
271 : #endif
272 :
273 : #if defined (__cpp_lib_is_swappable) && __cpp_lib_is_swappable >= 201603L
274 : # ifndef PLUMED_GCH_LIB_IS_SWAPPABLE
275 : # define PLUMED_GCH_LIB_IS_SWAPPABLE
276 : # endif
277 : #endif
278 :
279 : #if defined (__cpp_lib_allocator_traits_is_always_equal)
280 : # if __cpp_lib_allocator_traits_is_always_equal >= 201411L
281 : # ifndef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
282 : # define PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
283 : # endif
284 : # endif
285 : #endif
286 :
287 : #if defined (__cpp_lib_constexpr_memory) && __cpp_lib_constexpr_memory >= 201811L
288 : # ifndef PLUMED_GCH_LIB_CONSTEXPR_MEMORY
289 : # define PLUMED_GCH_LIB_CONSTEXPR_MEMORY
290 : # endif
291 : #endif
292 :
293 : // TODO:
294 : // Make sure we don't need any laundering in the internal class functions.
295 : // I also need some sort of test case to actually show where UB is occurring,
296 : // because it's still a bit unclear to me.
297 : #if defined (__cpp_lib_launder) && __cpp_lib_launder >= 201606L
298 : # ifndef PLUMED_GCH_LIB_LAUNDER
299 : # define PLUMED_GCH_LIB_LAUNDER
300 : # endif
301 : #endif
302 :
303 : // defined if the entire thing is available for constexpr
304 : #ifndef PLUMED_GCH_SMALL_VECTOR_CONSTEXPR
305 : # if defined (PLUMED_GCH_HAS_CPP20_CONSTEXPR) && defined (PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED) \
306 : && defined (PLUMED_GCH_LIB_CONSTEXPR_MEMORY)
307 : # define PLUMED_GCH_SMALL_VECTOR_CONSTEXPR constexpr
308 : # ifndef PLUMED_GCH_HAS_CONSTEXPR_SMALL_VECTOR
309 : # define PLUMED_GCH_HAS_CONSTEXPR_SMALL_VECTOR
310 : # endif
311 : # else
312 : # define PLUMED_GCH_SMALL_VECTOR_CONSTEXPR
313 : # endif
314 : #endif
315 :
316 : #ifndef PLUMED_GCH_SMALL_VECTOR_DEFAULT_SIZE
317 : # define PLUMED_GCH_SMALL_VECTOR_DEFAULT_SIZE 64
318 : #endif
319 :
320 : namespace PLMD {
321 : namespace gch
322 : {
323 :
324 : #ifdef PLUMED_GCH_LIB_CONCEPTS
325 :
326 : namespace concepts
327 : {
328 :
329 : template <typename T>
330 : concept Complete = requires { sizeof (T); };
331 :
332 : // Note: this mirrors the named requirements, not the standard concepts, so we don't require
333 : // the destructor to be noexcept for Destructible.
334 : template <typename T>
335 : concept Destructible = std::is_destructible<T>::value;
336 :
337 : template <typename T>
338 : concept TriviallyDestructible = std::is_trivially_destructible<T>::value;
339 :
340 : template <typename T>
341 : concept NoThrowDestructible = std::is_nothrow_destructible<T>::value;
342 :
343 : // Note: this mirrors the named requirements, not the standard library concepts,
344 : // so we don't require Destructible here.
345 :
346 : template <typename T, typename... Args>
347 : concept ConstructibleFrom = std::is_constructible<T, Args...>::value;
348 :
349 : template <typename T, typename... Args>
350 : concept NoThrowConstructibleFrom = std::is_nothrow_constructible<T, Args...>::value;
351 :
352 : template <typename From, typename To>
353 : concept ConvertibleTo =
354 : std::is_convertible<From, To>::value
355 : && requires (typename std::add_rvalue_reference<From>::type (&f) (void))
356 : {
357 : static_cast<To> (f ());
358 : };
359 :
360 : template <typename From, typename To>
361 : concept NoThrowConvertibleTo =
362 : std::is_nothrow_convertible<From, To>::value
363 : && requires (typename std::add_rvalue_reference<From>::type (&f) (void) noexcept)
364 : {
365 : { static_cast<To> (f ()) } noexcept;
366 : };
367 :
368 : // Note: std::default_initializable requires std::destructible.
369 : template <typename T>
370 : concept DefaultConstructible =
371 : ConstructibleFrom<T>
372 : && requires { T { }; }
373 : && requires { ::new (static_cast<void *> (nullptr)) T; };
374 :
375 : template <typename T>
376 : concept MoveAssignable = std::assignable_from<T&, T>;
377 :
378 : template <typename T>
379 : concept CopyAssignable =
380 : MoveAssignable<T>
381 : && std::assignable_from<T&, T&>
382 : && std::assignable_from<T&, const T&>
383 : && std::assignable_from<T&, const T>;
384 :
385 : template <typename T>
386 : concept MoveConstructible = ConstructibleFrom<T, T> && ConvertibleTo<T, T>;
387 :
388 : template <typename T>
389 : concept NoThrowMoveConstructible =
390 : NoThrowConstructibleFrom<T, T>
391 : && NoThrowConvertibleTo<T, T>;
392 :
393 : template <typename T>
394 : concept CopyConstructible =
395 : MoveConstructible<T>
396 : && ConstructibleFrom<T, T&> && ConvertibleTo< T&, T>
397 : && ConstructibleFrom<T, const T&> && ConvertibleTo<const T&, T>
398 : && ConstructibleFrom<T, const T > && ConvertibleTo<const T, T>;
399 :
400 : template <typename T>
401 : concept NoThrowCopyConstructible =
402 : NoThrowMoveConstructible<T>
403 : && NoThrowConstructibleFrom<T, T&> && NoThrowConvertibleTo< T&, T>
404 : && NoThrowConstructibleFrom<T, const T&> && NoThrowConvertibleTo<const T&, T>
405 : && NoThrowConstructibleFrom<T, const T > && NoThrowConvertibleTo<const T, T>;
406 :
407 : template <typename T>
408 : concept Swappable = std::swappable<T>;
409 :
410 : template <typename T>
411 : concept EqualityComparable = std::equality_comparable<T>;
412 :
413 : // T is a type
414 : // X is a Container
415 : // A is an Allocator
416 : // if X::allocator_type then
417 : // std::same_as<typename X::allocator_type,
418 : // typename std::allocator_traits<A>::template rebind_alloc<T>>
419 : // otherwise
420 : // no condition; we use std::allocator<T> regardless of A
421 : //
422 : // see [22.2.1].16
423 : template <typename T, typename X, typename A, typename ...Args>
424 : concept EmplaceConstructible =
425 : std::same_as<typename X::value_type, T>
426 : && ( ( requires { typename X::allocator_type; } // only perform this check if X is
427 : && std::same_as<typename X::allocator_type, // allocator-aware
428 : typename std::allocator_traits<A>::template rebind_alloc<T>>
429 : && ( requires (A m, T *p, Args&&... args)
430 : {
431 : m.construct (p, std::forward<Args> (args)...);
432 : }
433 : || requires (T *p, Args&&... args)
434 : {
435 : #if __cplusplus >= 202002L // c++20 fully featured
436 : { std::construct_at (p, std::forward<Args> (args)...) } -> std::same_as<T *>;
437 : #else
438 : ::new (std::declval<void *> ()) T (std::declval<Args> ()...);
439 : #endif
440 : }))
441 : || (! requires { typename X::allocator_type; }
442 : && requires (T *p, Args&&... args)
443 : {
444 : #if __cplusplus >= 202002L // c++20 fully featured
445 : { std::construct_at (p, std::forward<Args> (args)...) } -> std::same_as<T *>;
446 : #else
447 : ::new (std::declval<void *> ()) T (std::declval<Args> ()...);
448 : #endif
449 : }));
450 :
451 : template <typename T, typename X,
452 : typename A = typename std::conditional<requires { typename X::allocator_type; },
453 : typename X::allocator_type,
454 : std::allocator<T>>::type>
455 : concept DefaultInsertable = EmplaceConstructible<T, X, A>;
456 :
457 : template <typename T, typename X,
458 : typename A = typename std::conditional<requires { typename X::allocator_type; },
459 : typename X::allocator_type,
460 : std::allocator<T>>::type>
461 : concept MoveInsertable = EmplaceConstructible<T, X, A, T>;
462 :
463 : template <typename T, typename X,
464 : typename A = typename std::conditional<requires { typename X::allocator_type; },
465 : typename X::allocator_type,
466 : std::allocator<T>>::type>
467 : concept CopyInsertable = MoveInsertable<T, X, A>
468 : && EmplaceConstructible<T, X, A, T&>
469 : && EmplaceConstructible<T, X, A, const T&>;
470 :
471 : // same method as with EmplaceConstructible
472 : template <typename T, typename X,
473 : typename A = typename std::conditional<requires { typename X::allocator_type; },
474 : typename X::allocator_type,
475 : std::allocator<T>>::type>
476 : concept Erasable =
477 : std::same_as<typename X::value_type, T>
478 : && ( ( requires { typename X::allocator_type; } // if X is allocator aware
479 : && std::same_as<typename X::allocator_type,
480 : typename std::allocator_traits<A>::template rebind_alloc<T>>
481 : && ( requires (A m, T *p)
482 : {
483 : m.destroy (p);
484 : }
485 : || std::is_destructible<T>::value))
486 : || (! requires { typename X::allocator_type; }
487 : && std::is_destructible<T>::value));
488 :
489 : template <typename T>
490 : concept ContextuallyConvertibleToBool = std::constructible_from<bool, T>;
491 :
492 : template <typename T>
493 : concept BoolConstant = std::derived_from<T, std::true_type>
494 : || std::derived_from<T, std::false_type>;
495 :
496 : template <typename T>
497 : concept NullablePointer =
498 : EqualityComparable<T>
499 : && DefaultConstructible<T>
500 : && CopyConstructible<T>
501 : && CopyAssignable<T>
502 : && Destructible<T>
503 : && ConstructibleFrom<T, std::nullptr_t>
504 : && ConvertibleTo<std::nullptr_t, T>
505 : && requires (T p, T q, std::nullptr_t np)
506 : {
507 : T (np);
508 : { p = np } -> std::same_as<T&>;
509 : { p != q } -> ContextuallyConvertibleToBool;
510 : { p == np } -> ContextuallyConvertibleToBool;
511 : { np == p } -> ContextuallyConvertibleToBool;
512 : { p != np } -> ContextuallyConvertibleToBool;
513 : { np != p } -> ContextuallyConvertibleToBool;
514 : };
515 :
516 : static_assert ( NullablePointer<int *>);
517 : static_assert (! NullablePointer<int>);
518 :
519 : template <typename A, typename T, typename U = T *>
520 : concept AllocatorFor =
521 : NoThrowCopyConstructible<A>
522 : && requires (A a,
523 : typename std::allocator_traits<A>::template rebind_alloc<U> b,
524 : U xp,
525 : typename std::allocator_traits<A>::pointer p,
526 : typename std::allocator_traits<A>::const_pointer cp,
527 : typename std::allocator_traits<A>::void_pointer vp,
528 : typename std::allocator_traits<A>::const_void_pointer cvp,
529 : typename std::allocator_traits<A>::value_type& r,
530 : typename std::allocator_traits<A>::size_type n)
531 : {
532 : /** Inner types **/
533 : // A::pointer
534 : requires NullablePointer< typename std::allocator_traits<A>::pointer>;
535 : requires std::random_access_iterator<typename std::allocator_traits<A>::pointer>;
536 : requires std::contiguous_iterator< typename std::allocator_traits<A>::pointer>;
537 :
538 : // A::const_pointer
539 : requires NullablePointer< typename std::allocator_traits<A>::const_pointer>;
540 : requires std::random_access_iterator<typename std::allocator_traits<A>::const_pointer>;
541 : requires std::contiguous_iterator< typename std::allocator_traits<A>::const_pointer>;
542 :
543 : requires std::convertible_to<typename std::allocator_traits<A>::pointer,
544 : typename std::allocator_traits<A>::const_pointer>;
545 :
546 : // A::void_pointer
547 : requires NullablePointer<typename std::allocator_traits<A>::void_pointer>;
548 :
549 : requires std::convertible_to<typename std::allocator_traits<A>::pointer,
550 : typename std::allocator_traits<A>::void_pointer>;
551 :
552 : requires std::same_as<typename std::allocator_traits<A>::void_pointer,
553 : typename std::allocator_traits<decltype (b)>::void_pointer>;
554 :
555 : // A::const_void_pointer
556 : requires NullablePointer<typename std::allocator_traits<A>::const_void_pointer>;
557 :
558 : requires std::convertible_to<typename std::allocator_traits<A>::pointer,
559 : typename std::allocator_traits<A>::const_void_pointer>;
560 :
561 : requires std::convertible_to<typename std::allocator_traits<A>::const_pointer,
562 : typename std::allocator_traits<A>::const_void_pointer>;
563 :
564 : requires std::convertible_to<typename std::allocator_traits<A>::void_pointer,
565 : typename std::allocator_traits<A>::const_void_pointer>;
566 :
567 : requires std::same_as<typename std::allocator_traits<A>::const_void_pointer,
568 : typename std::allocator_traits<decltype (b)>::const_void_pointer>;
569 :
570 : // A::value_type
571 : typename A::value_type;
572 : requires std::same_as<typename A::value_type, T>;
573 : requires std::same_as<typename A::value_type,
574 : typename std::allocator_traits<A>::value_type>;
575 :
576 : // A::size_type
577 : requires std::unsigned_integral<typename std::allocator_traits<A>::size_type>;
578 :
579 : // A::difference_type
580 : requires std::signed_integral<typename std::allocator_traits<A>::difference_type>;
581 :
582 : // A::template rebind<U>::other [optional]
583 : requires ! requires { typename A::template rebind<U>::other; }
584 : || requires
585 : {
586 : requires std::same_as<decltype (b), typename A::template rebind<U>::other>;
587 : requires std::same_as<A, typename decltype (b)::template rebind<T>::other>;
588 : };
589 :
590 : /** Operations on pointers **/
591 : { *p } -> std::same_as<typename A::value_type&>;
592 : { *cp } -> std::same_as<const typename A::value_type&>;
593 :
594 : // Language in the standard implies that `decltype (p)` must either
595 : // be a raw pointer or implement `operator->`. There is no mention
596 : // of `std::to_address` or `std::pointer_traits<Ptr>::to_address`.
597 : requires std::same_as<decltype (p), typename A::value_type *>
598 : || requires
599 : {
600 : { p.operator-> () } -> std::same_as<typename A::value_type *>;
601 : };
602 :
603 : requires std::same_as<decltype (cp), const typename A::value_type *>
604 : || requires
605 : {
606 : { cp.operator-> () } -> std::same_as<const typename A::value_type *>;
607 : };
608 :
609 : { static_cast<decltype (p)> (vp) } -> std::same_as<decltype (p)>;
610 : { static_cast<decltype (cp)> (cvp) } -> std::same_as<decltype (cp)>;
611 :
612 : { std::pointer_traits<decltype (p)>::pointer_to (r) } -> std::same_as<decltype (p)>;
613 :
614 : /** Storage and lifetime operations **/
615 : // a.allocate (n)
616 : { a.allocate (n) } -> std::same_as<decltype (p)>;
617 :
618 : // a.allocate (n, cvp) [optional]
619 : requires ! requires { a.allocate (n, cvp); }
620 : || requires { { a.allocate (n, cvp) } -> std::same_as<decltype (p)>; };
621 :
622 : // a.deallocate (p, n)
623 : { a.deallocate (p, n) } -> std::convertible_to<void>;
624 :
625 : // a.max_size () [optional]
626 : requires ! requires { a.max_size (); }
627 : || requires { { a.max_size () } -> std::same_as<decltype (n)>; };
628 :
629 : // a.construct (xp, args) [optional]
630 : requires ! requires { a.construct (xp); }
631 : || requires { { a.construct (xp) } -> std::convertible_to<void>; };
632 :
633 : // a.destroy (xp) [optional]
634 : requires ! requires { a.destroy (xp); }
635 : || requires { { a.destroy (xp) } -> std::convertible_to<void>; };
636 :
637 : /** Relationship between instances **/
638 : requires NoThrowConstructibleFrom<A, decltype (b)>;
639 : requires NoThrowConstructibleFrom<A, decltype (std::move (b))>;
640 :
641 : requires BoolConstant<typename std::allocator_traits<A>::is_always_equal>;
642 :
643 : /** Influence on container operations **/
644 : // a.select_on_container_copy_construction () [optional]
645 : requires ! requires { a.select_on_container_copy_construction (); }
646 : || requires
647 : {
648 : { a.select_on_container_copy_construction () } -> std::same_as<A>;
649 : };
650 :
651 : requires BoolConstant<
652 : typename std::allocator_traits<A>::propagate_on_container_copy_assignment>;
653 :
654 : requires BoolConstant<
655 : typename std::allocator_traits<A>::propagate_on_container_move_assignment>;
656 :
657 : requires BoolConstant<
658 : typename std::allocator_traits<A>::propagate_on_container_swap>;
659 :
660 : { a == b } -> std::same_as<bool>;
661 : { a != b } -> std::same_as<bool>;
662 : }
663 : && requires (A a1, A a2)
664 : {
665 : { a1 == a2 } -> std::same_as<bool>;
666 : { a1 != a2 } -> std::same_as<bool>;
667 : };
668 :
669 : static_assert (AllocatorFor<std::allocator<int>, int>,
670 : "std::allocator<int> failed to meet Allocator concept requirements.");
671 :
672 : template <typename A>
673 : concept Allocator = AllocatorFor<A, typename A::value_type>;
674 :
675 : namespace small_vector
676 : {
677 :
678 : // Basically, these shut off the concepts if we have an incomplete type.
679 : // This namespace is only needed because of issues on Clang
680 : // preventing us from short-circuiting for incomplete types.
681 :
682 : template <typename T>
683 : concept Destructible =
684 : ! concepts::Complete<T> || concepts::Destructible<T>;
685 :
686 : template <typename T>
687 : concept MoveAssignable =
688 : ! concepts::Complete<T> || concepts::MoveAssignable<T>;
689 :
690 : template <typename T>
691 : concept CopyAssignable =
692 : ! concepts::Complete<T> || concepts::CopyAssignable<T>;
693 :
694 : template <typename T>
695 : concept MoveConstructible =
696 : ! concepts::Complete<T> || concepts::MoveConstructible<T>;
697 :
698 : template <typename T>
699 : concept CopyConstructible =
700 : ! concepts::Complete<T> || concepts::CopyConstructible<T>;
701 :
702 : template <typename T>
703 : concept Swappable =
704 : ! concepts::Complete<T> || concepts::Swappable<T>;
705 :
706 : template <typename T, typename SmallVector, typename Alloc>
707 : concept DefaultInsertable =
708 : ! concepts::Complete<T> || concepts::DefaultInsertable<T, SmallVector, Alloc>;
709 :
710 : template <typename T, typename SmallVector, typename Alloc>
711 : concept MoveInsertable =
712 : ! concepts::Complete<T> || concepts::MoveInsertable<T, SmallVector, Alloc>;
713 :
714 : template <typename T, typename SmallVector, typename Alloc>
715 : concept CopyInsertable =
716 : ! concepts::Complete<T> || concepts::CopyInsertable<T, SmallVector, Alloc>;
717 :
718 : template <typename T, typename SmallVector, typename Alloc>
719 : concept Erasable =
720 : ! concepts::Complete<T> || concepts::Erasable<T, SmallVector, Alloc>;
721 :
722 : template <typename T, typename SmallVector, typename Alloc, typename ...Args>
723 : concept EmplaceConstructible =
724 : ! concepts::Complete<T> || concepts::EmplaceConstructible<T, SmallVector, Alloc, Args...>;
725 :
726 : template <typename Alloc, typename T>
727 : concept AllocatorFor =
728 : ! concepts::Complete<T> || concepts::AllocatorFor<Alloc, T>;
729 :
730 : template <typename Alloc>
731 : concept Allocator = AllocatorFor<Alloc, typename Alloc::value_type>;
732 :
733 : } // namespace gch::concepts::small_vector
734 :
735 : } // namespace gch::concepts
736 :
737 : #endif
738 :
739 : template <typename Allocator>
740 : #ifdef PLUMED_GCH_LIB_CONCEPTS
741 : requires concepts::small_vector::Allocator<Allocator>
742 : #endif
743 : struct default_buffer_size;
744 :
745 : template <typename T,
746 : unsigned InlineCapacity = default_buffer_size<std::allocator<T>>::value,
747 : typename Allocator = std::allocator<T>>
748 : #ifdef PLUMED_GCH_LIB_CONCEPTS
749 : requires concepts::small_vector::AllocatorFor<Allocator, T>
750 : #endif
751 : class small_vector;
752 :
753 : template <typename Allocator>
754 : #ifdef PLUMED_GCH_LIB_CONCEPTS
755 : requires concepts::small_vector::Allocator<Allocator>
756 : #endif
757 : struct default_buffer_size
758 : {
759 : private:
760 : template <typename, typename Enable = void>
761 : struct is_complete
762 : : std::false_type
763 : { };
764 :
765 : template <typename U>
766 : struct is_complete<U, decltype (static_cast<void> (sizeof (U)))>
767 : : std::true_type
768 : { };
769 :
770 : public:
771 : using allocator_type = Allocator;
772 : using value_type = typename std::allocator_traits<allocator_type>::value_type;
773 : using empty_small_vector = small_vector<value_type, 0, allocator_type>;
774 :
775 : static_assert (is_complete<value_type>::value,
776 : "Calculation of a default number of elements requires that `T` be complete.");
777 :
778 : static constexpr
779 : unsigned
780 : buffer_max = 256;
781 :
782 : static constexpr
783 : unsigned
784 : ideal_total = PLUMED_GCH_SMALL_VECTOR_DEFAULT_SIZE;
785 :
786 : #ifndef PLUMED_GCH_UNRESTRICTED_DEFAULT_BUFFER_SIZE
787 :
788 : // FIXME: Some compilers will not emit the error from this static_assert
789 : // while instantiating a small_vector, and attribute the mistake
790 : // to some random other function.
791 : // static_assert (sizeof (value_type) <= buffer_max, "`sizeof (T)` too large");
792 :
793 : #endif
794 :
795 : static constexpr
796 : unsigned
797 : ideal_buffer = ideal_total - sizeof (empty_small_vector);
798 :
799 : static_assert (sizeof (empty_small_vector) != 0,
800 : "Empty `small_vector` should not have size 0.");
801 :
802 : static_assert (ideal_buffer < ideal_total,
803 : "Empty `small_vector` is larger than ideal_total.");
804 :
805 : static constexpr
806 : unsigned
807 : value = (sizeof (value_type) <= ideal_buffer) ? (ideal_buffer / sizeof (value_type)) : 1;
808 : };
809 :
810 : #ifdef PLUMED_GCH_VARIABLE_TEMPLATES
811 :
812 : template <typename Allocator>
813 : PLUMED_GCH_INLINE_VARIABLE constexpr
814 : unsigned
815 : default_buffer_size_v = default_buffer_size<Allocator>::value;
816 :
817 : #endif
818 :
819 : template <typename Pointer, typename DifferenceType>
820 : class small_vector_iterator
821 : {
822 : public:
823 : using difference_type = DifferenceType;
824 : using value_type = typename std::iterator_traits<Pointer>::value_type;
825 : using pointer = typename std::iterator_traits<Pointer>::pointer;
826 : using reference = typename std::iterator_traits<Pointer>::reference;
827 : using iterator_category = typename std::iterator_traits<Pointer>::iterator_category;
828 : #ifdef PLUMED_GCH_LIB_CONCEPTS
829 : using iterator_concept = std::contiguous_iterator_tag;
830 : #endif
831 :
832 : // small_vector_iterator (void) = impl;
833 : small_vector_iterator (const small_vector_iterator&) = default;
834 : small_vector_iterator (small_vector_iterator&&) noexcept = default;
835 : small_vector_iterator& operator= (const small_vector_iterator&) = default;
836 : small_vector_iterator& operator= (small_vector_iterator&&) noexcept = default;
837 : ~small_vector_iterator (void) = default;
838 :
839 : #ifdef NDEBUG
840 : small_vector_iterator (void) = default;
841 : #else
842 : constexpr
843 : small_vector_iterator (void) noexcept
844 : : m_ptr ()
845 : { }
846 : #endif
847 :
848 : constexpr explicit
849 : small_vector_iterator (const Pointer& p) noexcept
850 : : m_ptr (p)
851 : { }
852 :
853 : template <typename U, typename D,
854 : typename std::enable_if<std::is_convertible<U, Pointer>::value>::type * = nullptr>
855 : constexpr PLUMED_GCH_IMPLICIT_CONVERSION
856 : small_vector_iterator (const small_vector_iterator<U, D>& other) noexcept
857 : : m_ptr (other.base ())
858 : { }
859 :
860 : PLUMED_GCH_CPP14_CONSTEXPR
861 : small_vector_iterator&
862 : operator++ (void) noexcept
863 : {
864 : ++m_ptr;
865 : return *this;
866 : }
867 :
868 : PLUMED_GCH_CPP14_CONSTEXPR
869 : small_vector_iterator
870 : operator++ (int) noexcept
871 : {
872 : return small_vector_iterator (m_ptr++);
873 : }
874 :
875 : PLUMED_GCH_CPP14_CONSTEXPR
876 : small_vector_iterator&
877 : operator-- (void) noexcept
878 : {
879 1797525 : --m_ptr;
880 : return *this;
881 : }
882 :
883 : PLUMED_GCH_CPP14_CONSTEXPR
884 : small_vector_iterator
885 : operator-- (int) noexcept
886 : {
887 : return small_vector_iterator (m_ptr--);
888 : }
889 :
890 : PLUMED_GCH_CPP14_CONSTEXPR
891 : small_vector_iterator&
892 : operator+= (difference_type n) noexcept
893 : {
894 : m_ptr += n;
895 : return *this;
896 : }
897 :
898 : constexpr
899 : small_vector_iterator
900 : operator+ (difference_type n) const noexcept
901 : {
902 12826778 : return small_vector_iterator (m_ptr + n);
903 : }
904 :
905 : PLUMED_GCH_CPP14_CONSTEXPR
906 : small_vector_iterator&
907 : operator-= (difference_type n) noexcept
908 : {
909 : m_ptr -= n;
910 : return *this;
911 : }
912 :
913 : constexpr
914 : small_vector_iterator
915 : operator- (difference_type n) const noexcept
916 : {
917 2386656 : return small_vector_iterator (m_ptr - n);
918 : }
919 :
920 : constexpr
921 : reference
922 : operator* (void) const noexcept
923 : {
924 : #ifdef PLUMED_GCH_LIB_LAUNDER
925 : return launder_and_dereference (m_ptr);
926 : #else
927 : return *m_ptr;
928 : #endif
929 : }
930 :
931 : constexpr
932 : pointer
933 : operator-> (void) const noexcept
934 : {
935 : return get_pointer (m_ptr);
936 : }
937 :
938 : constexpr
939 : reference
940 : operator[] (difference_type n) const noexcept
941 : {
942 : #ifdef PLUMED_GCH_LIB_LAUNDER
943 142075517 : return launder_and_dereference (m_ptr + n);
944 : #else
945 : return m_ptr[n];
946 : #endif
947 : }
948 :
949 : constexpr
950 : const Pointer&
951 : base (void) const noexcept
952 : {
953 : return m_ptr;
954 : }
955 :
956 : private:
957 : template <typename Ptr = Pointer,
958 : typename std::enable_if<std::is_pointer<Ptr>::value, bool>::type = true>
959 : static constexpr
960 : pointer
961 : get_pointer (Pointer ptr) noexcept
962 : {
963 : return ptr;
964 : }
965 :
966 : template <typename Ptr = Pointer,
967 : typename std::enable_if<! std::is_pointer<Ptr>::value, bool>::type = false>
968 : static constexpr
969 : pointer
970 : get_pointer (Pointer ptr) noexcept
971 : {
972 : // Given the requirements for Allocator, Pointer must either be a raw pointer, or
973 : // have a defined operator-> which returns a raw pointer.
974 : return ptr.operator-> ();
975 : }
976 :
977 : #ifdef PLUMED_GCH_LIB_LAUNDER
978 :
979 : template <typename Ptr = Pointer,
980 : typename std::enable_if<std::is_pointer<Ptr>::value, bool>::type = true>
981 : static constexpr
982 : reference
983 : launder_and_dereference (Pointer ptr) noexcept
984 : {
985 : return *std::launder (ptr);
986 : }
987 :
988 : template <typename Ptr = Pointer,
989 : typename std::enable_if<! std::is_pointer<Ptr>::value, bool>::type = false>
990 : static constexpr
991 : reference
992 : launder_and_dereference (Pointer ptr) noexcept
993 : {
994 : return *ptr;
995 : }
996 :
997 : #endif
998 :
999 : Pointer m_ptr;
1000 : };
1001 :
1002 : #ifdef PLUMED_GCH_LIB_THREE_WAY_COMPARISON
1003 :
1004 : template <typename PointerLHS, typename DifferenceTypeLHS,
1005 : typename PointerRHS, typename DifferenceTypeRHS>
1006 : constexpr
1007 : bool
1008 : operator== (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1009 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs)
1010 : noexcept (noexcept (lhs.base () == rhs.base ()))
1011 : requires requires { { lhs.base () == rhs.base () } -> std::convertible_to<bool>; }
1012 : {
1013 : return lhs.base () == rhs.base ();
1014 : }
1015 :
1016 : template <typename Pointer, typename DifferenceType>
1017 : constexpr
1018 : bool
1019 : operator== (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1020 : const small_vector_iterator<Pointer, DifferenceType>& rhs)
1021 : noexcept (noexcept (lhs.base () == rhs.base ()))
1022 : requires requires { { lhs.base () == rhs.base () } -> std::convertible_to<bool>; }
1023 : {
1024 : return lhs.base () == rhs.base ();
1025 : }
1026 :
1027 : template <typename PointerLHS, typename DifferenceTypeLHS,
1028 : typename PointerRHS, typename DifferenceTypeRHS>
1029 : requires std::three_way_comparable_with<PointerLHS, PointerRHS>
1030 : constexpr
1031 : auto
1032 : operator<=> (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1033 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs)
1034 : noexcept (noexcept (lhs.base () <=> rhs.base ()))
1035 : {
1036 : return lhs.base () <=> rhs.base ();
1037 : }
1038 :
1039 : template <typename Pointer, typename DifferenceType>
1040 : requires std::three_way_comparable<Pointer>
1041 : constexpr
1042 : auto
1043 : operator<=> (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1044 : const small_vector_iterator<Pointer, DifferenceType>& rhs)
1045 : noexcept (noexcept (lhs.base () <=> rhs.base ()))
1046 : {
1047 : return lhs.base () <=> rhs.base ();
1048 : }
1049 :
1050 : template <typename PointerLHS, typename DifferenceTypeLHS,
1051 : typename PointerRHS, typename DifferenceTypeRHS>
1052 : constexpr
1053 : auto
1054 : operator<=> (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1055 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs)
1056 : noexcept (noexcept (lhs.base () < rhs.base ()) && noexcept (rhs.base () < lhs.base ()))
1057 : {
1058 : using ordering = std::weak_ordering;
1059 : return (lhs.base () < rhs.base ()) ? ordering::less
1060 : : (rhs.base () < lhs.base ()) ? ordering::greater
1061 : : ordering::equivalent;
1062 : }
1063 :
1064 : template <typename Pointer, typename DifferenceType>
1065 : constexpr
1066 : auto
1067 : operator<=> (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1068 : const small_vector_iterator<Pointer, DifferenceType>& rhs)
1069 : noexcept (noexcept (lhs.base () < rhs.base ()) && noexcept (rhs.base () < lhs.base ()))
1070 : {
1071 : using ordering = std::weak_ordering;
1072 : return (lhs.base () < rhs.base ()) ? ordering::less
1073 : : (rhs.base () < lhs.base ()) ? ordering::greater
1074 : : ordering::equivalent;
1075 : }
1076 :
1077 : #else
1078 :
1079 : // Note: Passing this on from "Gaby" in stl_iterator.h -- templated
1080 : // comparisons in generic code should have overloads for both
1081 : // homogenous and heterogeneous types. This is because we get
1082 : // ambiguous overload resolution when std::rel_ops is visible
1083 : // (ie. `using namespace std::rel_ops`).
1084 :
1085 : template <typename PointerLHS, typename DifferenceTypeLHS,
1086 : typename PointerRHS, typename DifferenceTypeRHS>
1087 : constexpr
1088 : bool
1089 : operator== (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1090 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs) noexcept
1091 : {
1092 : return lhs.base () == rhs.base ();
1093 : }
1094 :
1095 : template <typename Pointer, typename DifferenceType>
1096 : constexpr
1097 : bool
1098 : operator== (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1099 : const small_vector_iterator<Pointer, DifferenceType>& rhs) noexcept
1100 : {
1101 : return lhs.base () == rhs.base ();
1102 : }
1103 :
1104 : template <typename PointerLHS, typename DifferenceTypeLHS,
1105 : typename PointerRHS, typename DifferenceTypeRHS>
1106 : constexpr
1107 : bool
1108 : operator!= (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1109 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs) noexcept
1110 : {
1111 : return lhs.base () != rhs.base ();
1112 : }
1113 :
1114 : template <typename Pointer, typename DifferenceType>
1115 : constexpr
1116 : bool
1117 : operator!= (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1118 : const small_vector_iterator<Pointer, DifferenceType>& rhs) noexcept
1119 : {
1120 : return lhs.base () != rhs.base ();
1121 : }
1122 :
1123 : template <typename PointerLHS, typename DifferenceTypeLHS,
1124 : typename PointerRHS, typename DifferenceTypeRHS>
1125 : constexpr
1126 : bool
1127 : operator< (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1128 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs) noexcept
1129 : {
1130 : return lhs.base () < rhs.base ();
1131 : }
1132 :
1133 : template <typename Pointer, typename DifferenceType>
1134 : constexpr
1135 : bool
1136 : operator< (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1137 : const small_vector_iterator<Pointer, DifferenceType>& rhs) noexcept
1138 : {
1139 : return lhs.base () < rhs.base ();
1140 : }
1141 :
1142 : template <typename PointerLHS, typename DifferenceTypeLHS,
1143 : typename PointerRHS, typename DifferenceTypeRHS>
1144 : constexpr
1145 : bool
1146 : operator>= (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1147 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs) noexcept
1148 : {
1149 : return lhs.base () >= rhs.base ();
1150 : }
1151 :
1152 : template <typename Pointer, typename DifferenceType>
1153 : constexpr
1154 : bool
1155 : operator>= (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1156 : const small_vector_iterator<Pointer, DifferenceType>& rhs) noexcept
1157 : {
1158 : return lhs.base () >= rhs.base ();
1159 : }
1160 :
1161 : template <typename PointerLHS, typename DifferenceTypeLHS,
1162 : typename PointerRHS, typename DifferenceTypeRHS>
1163 : constexpr
1164 : bool
1165 : operator> (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1166 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs) noexcept
1167 : {
1168 : return lhs.base () > rhs.base ();
1169 : }
1170 :
1171 : template <typename Pointer, typename DifferenceType>
1172 : constexpr
1173 : bool
1174 : operator> (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1175 : const small_vector_iterator<Pointer, DifferenceType>& rhs) noexcept
1176 : {
1177 : return lhs.base () > rhs.base ();
1178 : }
1179 :
1180 : template <typename PointerLHS, typename DifferenceTypeLHS,
1181 : typename PointerRHS, typename DifferenceTypeRHS>
1182 : constexpr
1183 : bool
1184 : operator<= (const small_vector_iterator<PointerLHS, DifferenceTypeLHS>& lhs,
1185 : const small_vector_iterator<PointerRHS, DifferenceTypeRHS>& rhs) noexcept
1186 : {
1187 : return lhs.base () <= rhs.base ();
1188 : }
1189 :
1190 : template <typename Pointer, typename DifferenceType>
1191 : constexpr
1192 : bool
1193 : operator<= (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1194 : const small_vector_iterator<Pointer, DifferenceType>& rhs) noexcept
1195 : {
1196 : return lhs.base () <= rhs.base ();
1197 : }
1198 :
1199 : #endif
1200 :
1201 : template <typename PointerLHS, typename PointerRHS, typename DifferenceType>
1202 : constexpr
1203 : DifferenceType
1204 : operator- (const small_vector_iterator<PointerLHS, DifferenceType>& lhs,
1205 : const small_vector_iterator<PointerRHS, DifferenceType>& rhs) noexcept
1206 : {
1207 : return static_cast<DifferenceType> (lhs.base () - rhs.base ());
1208 : }
1209 :
1210 : template <typename Pointer, typename DifferenceType>
1211 : constexpr
1212 : DifferenceType
1213 : operator- (const small_vector_iterator<Pointer, DifferenceType>& lhs,
1214 : const small_vector_iterator<Pointer, DifferenceType>& rhs) noexcept
1215 : {
1216 6755185 : return static_cast<DifferenceType> (lhs.base () - rhs.base ());
1217 : }
1218 :
1219 : template <typename Pointer, typename DifferenceType>
1220 : constexpr
1221 : small_vector_iterator<Pointer, DifferenceType>
1222 : operator+ (DifferenceType n, const small_vector_iterator<Pointer, DifferenceType>& it) noexcept
1223 : {
1224 : return it + n;
1225 : }
1226 :
1227 : namespace detail
1228 : {
1229 :
1230 : #ifndef PLUMED_GCH_LIB_IS_SWAPPABLE
1231 :
1232 : namespace small_vector_adl
1233 : {
1234 :
1235 : using std::swap;
1236 :
1237 : template <typename T, typename Enable = void>
1238 : struct is_nothrow_swappable
1239 : : std::false_type
1240 : { };
1241 :
1242 : template <typename T>
1243 : struct is_nothrow_swappable<T, decltype (swap (std::declval<T&> (), std::declval<T&> ()))>
1244 : : std::integral_constant<bool, noexcept (swap (std::declval<T&> (), std::declval<T&> ()))>
1245 : { };
1246 :
1247 : }
1248 :
1249 : #endif
1250 :
1251 : template <typename T, unsigned InlineCapacity>
1252 : class inline_storage
1253 : {
1254 : public:
1255 : using value_ty = T;
1256 :
1257 : inline_storage (void) = default;
1258 : inline_storage (const inline_storage&) = delete;
1259 : inline_storage (inline_storage&&) noexcept = delete;
1260 : inline_storage& operator= (const inline_storage&) = delete;
1261 : inline_storage& operator= (inline_storage&&) noexcept = delete;
1262 : ~inline_storage (void) = default;
1263 :
1264 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
1265 : value_ty *
1266 : get_inline_ptr (void) noexcept
1267 : {
1268 215674 : return static_cast<value_ty *> (static_cast<void *> (std::addressof (*m_data)));
1269 : }
1270 :
1271 : PLUMED_GCH_NODISCARD constexpr
1272 : const value_ty *
1273 : get_inline_ptr (void) const noexcept
1274 : {
1275 : return static_cast<const value_ty *> (static_cast<const void *> (std::addressof (*m_data)));
1276 : }
1277 :
1278 : static constexpr
1279 : std::size_t
1280 : element_size (void) noexcept
1281 : {
1282 : return sizeof (value_ty);
1283 : }
1284 :
1285 : static constexpr
1286 : std::size_t
1287 : alignment (void) noexcept
1288 : {
1289 : return alignof (value_ty);
1290 : }
1291 :
1292 : static constexpr
1293 : unsigned
1294 : num_elements (void) noexcept
1295 : {
1296 : return InlineCapacity;
1297 : }
1298 :
1299 : static constexpr
1300 : std::size_t
1301 : num_bytes (void) noexcept
1302 : {
1303 : return num_elements () * element_size ();
1304 : }
1305 :
1306 : private:
1307 : typename std::aligned_storage<element_size (), alignment ()>::type m_data[num_elements ()];
1308 : };
1309 :
1310 : template <typename T>
1311 : class PLUMED_GCH_EMPTY_BASE inline_storage<T, 0>
1312 : {
1313 : public:
1314 : using value_ty = T;
1315 :
1316 : inline_storage (void) = default;
1317 : inline_storage (const inline_storage&) = delete;
1318 : inline_storage (inline_storage&&) noexcept = delete;
1319 : inline_storage& operator= (const inline_storage&) = delete;
1320 : inline_storage& operator= (inline_storage&&) noexcept = delete;
1321 : ~inline_storage (void) = default;
1322 :
1323 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
1324 : value_ty *
1325 : get_inline_ptr (void) noexcept
1326 : {
1327 : return nullptr;
1328 : }
1329 :
1330 : PLUMED_GCH_NODISCARD constexpr
1331 : const value_ty *
1332 : get_inline_ptr (void) const noexcept
1333 : {
1334 : return nullptr;
1335 : }
1336 :
1337 : static constexpr
1338 : std::size_t
1339 : element_size (void) noexcept
1340 : {
1341 : return sizeof (value_ty);
1342 : }
1343 :
1344 : static constexpr
1345 : std::size_t
1346 : alignment (void) noexcept
1347 : {
1348 : return alignof (value_ty);
1349 : }
1350 :
1351 : static constexpr
1352 : unsigned
1353 : num_elements (void) noexcept
1354 : {
1355 : return 0;
1356 : }
1357 :
1358 : static constexpr
1359 : std::size_t
1360 : num_bytes (void) noexcept
1361 : {
1362 : return 0;
1363 : }
1364 : };
1365 :
1366 : template <typename Allocator, bool AvailableForEBO = std::is_empty<Allocator>::value
1367 : #ifdef PLUMED_GCH_LIB_IS_FINAL
1368 : &&! std::is_final<Allocator>::value
1369 : #endif // If you are using this with C++11 just don't use an allocator marked as final :P
1370 : >
1371 : class allocator_inliner;
1372 :
1373 : template <typename Allocator>
1374 : class PLUMED_GCH_EMPTY_BASE allocator_inliner<Allocator, true>
1375 : : private Allocator
1376 : {
1377 : using alloc_traits = std::allocator_traits<Allocator>;
1378 :
1379 : static constexpr
1380 : bool
1381 : copy_assign_is_noop = ! alloc_traits::propagate_on_container_copy_assignment::value;
1382 :
1383 : static constexpr
1384 : bool
1385 : move_assign_is_noop = ! alloc_traits::propagate_on_container_move_assignment::value;
1386 :
1387 : static constexpr
1388 : bool
1389 : swap_is_noop = ! alloc_traits::propagate_on_container_swap::value;
1390 :
1391 : template <bool IsNoOp = copy_assign_is_noop,
1392 : typename std::enable_if<IsNoOp, bool>::type = true>
1393 : PLUMED_GCH_CPP20_CONSTEXPR
1394 : void
1395 : maybe_assign (const allocator_inliner&) noexcept { }
1396 :
1397 : template <bool IsNoOp = copy_assign_is_noop,
1398 : typename std::enable_if<! IsNoOp, bool>::type = false>
1399 : PLUMED_GCH_CPP20_CONSTEXPR
1400 : void
1401 : maybe_assign (const allocator_inliner& other)
1402 : noexcept (noexcept (std::declval<Allocator&> ().operator= (other)))
1403 : {
1404 : Allocator::operator= (other);
1405 : }
1406 :
1407 : template <bool IsNoOp = move_assign_is_noop,
1408 : typename std::enable_if<IsNoOp, bool>::type = true>
1409 : PLUMED_GCH_CPP20_CONSTEXPR
1410 : void
1411 : maybe_assign (allocator_inliner&&) noexcept { }
1412 :
1413 : template <bool IsNoOp = move_assign_is_noop,
1414 : typename std::enable_if<! IsNoOp, bool>::type = false>
1415 : PLUMED_GCH_CPP20_CONSTEXPR
1416 : void
1417 : maybe_assign (allocator_inliner&& other)
1418 : noexcept (noexcept (std::declval<Allocator&> ().operator= (std::move (other))))
1419 : {
1420 : Allocator::operator= (std::move (other));
1421 : }
1422 :
1423 : public:
1424 : allocator_inliner (void) = default;
1425 : allocator_inliner (const allocator_inliner&) = default;
1426 : allocator_inliner (allocator_inliner&&) noexcept = default;
1427 : // allocator_inliner& operator= (const allocator_inliner&) = impl;
1428 : // allocator_inliner& operator= (allocator_inliner&&) noexcept = impl;
1429 : ~allocator_inliner (void) = default;
1430 :
1431 : constexpr explicit
1432 : allocator_inliner (const Allocator& alloc) noexcept
1433 : : Allocator (alloc)
1434 : { }
1435 :
1436 : PLUMED_GCH_CPP20_CONSTEXPR
1437 : allocator_inliner&
1438 : operator= (const allocator_inliner& other)
1439 : noexcept (noexcept (std::declval<allocator_inliner&> ().maybe_assign (other)))
1440 : {
1441 : assert (&other != this
1442 : && "`allocator_inliner` should not participate in self-copy-assignment.");
1443 : maybe_assign (other);
1444 : return *this;
1445 : }
1446 :
1447 : PLUMED_GCH_CPP20_CONSTEXPR
1448 : allocator_inliner&
1449 : operator= (allocator_inliner&& other)
1450 : noexcept (noexcept (std::declval<allocator_inliner&> ().maybe_assign (std::move (other))))
1451 : {
1452 : assert (&other != this
1453 : && "`allocator_inliner` should not participate in self-move-assignment.");
1454 : maybe_assign (std::move (other));
1455 : return *this;
1456 : }
1457 :
1458 : PLUMED_GCH_CPP14_CONSTEXPR
1459 : Allocator&
1460 : allocator_ref (void) noexcept
1461 : {
1462 : return *this;
1463 : }
1464 :
1465 : constexpr
1466 : const Allocator&
1467 : allocator_ref (void) const noexcept
1468 : {
1469 : return *this;
1470 : }
1471 :
1472 : template <bool IsNoOp = swap_is_noop,
1473 : typename std::enable_if<IsNoOp, bool>::type = true>
1474 : PLUMED_GCH_CPP20_CONSTEXPR
1475 : void
1476 : swap (allocator_inliner&)
1477 : { }
1478 :
1479 : template <bool IsNoOp = swap_is_noop,
1480 : typename std::enable_if<! IsNoOp, bool>::type = false>
1481 : PLUMED_GCH_CPP20_CONSTEXPR
1482 : void
1483 : swap (allocator_inliner& other)
1484 : {
1485 : using std::swap;
1486 : swap (static_cast<Allocator&> (*this), static_cast<Allocator&> (other));
1487 : }
1488 : };
1489 :
1490 : template <typename Allocator>
1491 : class allocator_inliner<Allocator, false>
1492 : {
1493 : using alloc_traits = std::allocator_traits<Allocator>;
1494 :
1495 : static constexpr
1496 : bool
1497 : copy_assign_is_noop = ! alloc_traits::propagate_on_container_copy_assignment::value;
1498 :
1499 : static constexpr
1500 : bool
1501 : move_assign_is_noop = ! alloc_traits::propagate_on_container_move_assignment::value;
1502 :
1503 : static constexpr
1504 : bool
1505 : swap_is_noop = ! alloc_traits::propagate_on_container_swap::value;
1506 :
1507 : template <bool IsNoOp = copy_assign_is_noop,
1508 : typename std::enable_if<IsNoOp, bool>::type = true>
1509 : PLUMED_GCH_CPP20_CONSTEXPR
1510 : void
1511 : maybe_assign (const allocator_inliner&) noexcept { }
1512 :
1513 : template <bool IsNoOp = copy_assign_is_noop,
1514 : typename std::enable_if<! IsNoOp, bool>::type = false>
1515 : PLUMED_GCH_CPP20_CONSTEXPR
1516 : void
1517 : maybe_assign (const allocator_inliner& other)
1518 : noexcept (noexcept (std::declval<decltype (other.m_alloc)&> () = other.m_alloc))
1519 : {
1520 : m_alloc = other.m_alloc;
1521 : }
1522 :
1523 : template <bool IsNoOp = move_assign_is_noop,
1524 : typename std::enable_if<IsNoOp, bool>::type = true>
1525 : PLUMED_GCH_CPP20_CONSTEXPR
1526 : void
1527 : maybe_assign (allocator_inliner&&) noexcept { }
1528 :
1529 : template <bool IsNoOp = move_assign_is_noop,
1530 : typename std::enable_if<! IsNoOp, bool>::type = false>
1531 : PLUMED_GCH_CPP20_CONSTEXPR
1532 : void
1533 : maybe_assign (allocator_inliner&& other)
1534 : noexcept (noexcept (std::declval<decltype (other.m_alloc)&> () = std::move (other.m_alloc)))
1535 : {
1536 : m_alloc = std::move (other.m_alloc);
1537 : }
1538 :
1539 : public:
1540 : allocator_inliner (void) = default;
1541 : allocator_inliner (const allocator_inliner&) = default;
1542 : allocator_inliner (allocator_inliner&&) noexcept = default;
1543 : // allocator_inliner& operator= (const allocator_inliner&) = impl;
1544 : // allocator_inliner& operator= (allocator_inliner&&) noexcept = impl;
1545 : ~allocator_inliner (void) = default;
1546 :
1547 : PLUMED_GCH_CPP20_CONSTEXPR explicit
1548 : allocator_inliner (const Allocator& alloc) noexcept
1549 : : m_alloc (alloc)
1550 : { }
1551 :
1552 : PLUMED_GCH_CPP20_CONSTEXPR
1553 : allocator_inliner&
1554 : operator= (const allocator_inliner& other)
1555 : noexcept (noexcept (std::declval<allocator_inliner&> ().maybe_assign (other)))
1556 : {
1557 : assert (&other != this
1558 : && "`allocator_inliner` should not participate in self-copy-assignment.");
1559 : maybe_assign (other);
1560 : return *this;
1561 : }
1562 :
1563 : PLUMED_GCH_CPP20_CONSTEXPR
1564 : allocator_inliner&
1565 : operator= (allocator_inliner&& other)
1566 : noexcept (noexcept (std::declval<allocator_inliner&> ().maybe_assign (std::move (other))))
1567 : {
1568 : assert (&other != this
1569 : && "`allocator_inliner` should not participate in self-move-assignment.");
1570 : maybe_assign (std::move (other));
1571 : return *this;
1572 : }
1573 :
1574 : PLUMED_GCH_CPP14_CONSTEXPR
1575 : Allocator&
1576 : allocator_ref (void) noexcept
1577 : {
1578 : return m_alloc;
1579 : }
1580 :
1581 : constexpr
1582 : const Allocator&
1583 : allocator_ref (void) const noexcept
1584 : {
1585 : return m_alloc;
1586 : }
1587 :
1588 : template <bool IsNoOp = swap_is_noop,
1589 : typename std::enable_if<IsNoOp, bool>::type = true>
1590 : PLUMED_GCH_CPP20_CONSTEXPR
1591 : void
1592 : swap (allocator_inliner&)
1593 : { }
1594 :
1595 : template <bool IsNoOp = swap_is_noop,
1596 : typename std::enable_if<! IsNoOp, bool>::type = false>
1597 : PLUMED_GCH_CPP20_CONSTEXPR
1598 : void
1599 : swap (allocator_inliner& other)
1600 : {
1601 : using std::swap;
1602 : swap (m_alloc, other.m_alloc);
1603 : }
1604 :
1605 : private:
1606 : Allocator m_alloc;
1607 : };
1608 :
1609 : template <typename Allocator>
1610 : class PLUMED_GCH_EMPTY_BASE allocator_interface
1611 : : public allocator_inliner<Allocator>
1612 : {
1613 : public:
1614 : template <typename, typename = void>
1615 : struct is_complete
1616 : : std::false_type
1617 : { };
1618 :
1619 : template <typename U>
1620 : struct is_complete<U, decltype (static_cast<void> (sizeof (U)))>
1621 : : std::true_type
1622 : { };
1623 :
1624 : using size_type = typename std::allocator_traits<Allocator>::size_type;
1625 :
1626 : // If difference_type is larger than size_type then we need
1627 : // to rectify that problem.
1628 : using difference_type = typename std::conditional<
1629 : (
1630 : static_cast<std::size_t> ((std::numeric_limits<size_type>::max) ())
1631 : < // less-than
1632 : static_cast<std::size_t> ((std::numeric_limits<
1633 : typename std::allocator_traits<Allocator>::difference_type>::max) ())
1634 : ),
1635 : typename std::make_signed<size_type>::type,
1636 : typename std::allocator_traits<Allocator>::difference_type>::type;
1637 :
1638 : private:
1639 : using alloc_base = allocator_inliner<Allocator>;
1640 :
1641 : protected:
1642 : using alloc_ty = Allocator;
1643 : using alloc_traits = std::allocator_traits<alloc_ty>;
1644 : using value_ty = typename alloc_traits::value_type;
1645 : using ptr = typename alloc_traits::pointer;
1646 : using cptr = typename alloc_traits::const_pointer;
1647 : using vptr = typename alloc_traits::void_pointer;
1648 : using cvptr = typename alloc_traits::const_void_pointer;
1649 :
1650 : // Select the fastest types larger than the user-facing types. These are only intended for
1651 : // internal computations, and should not have any memory footprint visible to consumers.
1652 : using size_ty =
1653 : typename std::conditional<
1654 : (sizeof (size_type) <= sizeof (std::uint8_t)),
1655 : std::uint_fast8_t,
1656 : typename std::conditional<
1657 : (sizeof (size_type) <= sizeof (std::uint16_t)),
1658 : std::uint_fast16_t,
1659 : typename std::conditional<
1660 : (sizeof (size_type) <= sizeof (std::uint32_t)),
1661 : std::uint_fast32_t,
1662 : typename std::conditional<
1663 : (sizeof (size_type) <= sizeof (std::uint64_t)),
1664 : std::uint_fast64_t,
1665 : size_type
1666 : >::type
1667 : >::type
1668 : >::type
1669 : >::type;
1670 :
1671 : using diff_ty =
1672 : typename std::conditional<
1673 : (sizeof (difference_type) <= sizeof (std::int8_t)),
1674 : std::int_fast8_t,
1675 : typename std::conditional<
1676 : (sizeof (difference_type) <= sizeof (std::int16_t)),
1677 : std::int_fast16_t,
1678 : typename std::conditional<
1679 : (sizeof (difference_type) <= sizeof (std::int32_t)),
1680 : std::int_fast32_t,
1681 : typename std::conditional<
1682 : (sizeof (difference_type) <= sizeof (std::int64_t)),
1683 : std::int_fast64_t,
1684 : difference_type
1685 : >::type
1686 : >::type
1687 : >::type
1688 : >::type;
1689 :
1690 : using alloc_base::allocator_ref;
1691 :
1692 : private:
1693 : template <typename ...>
1694 : using void_t = void;
1695 :
1696 : template <bool B>
1697 : using bool_constant = std::integral_constant<bool, B>;
1698 :
1699 : template <typename V, typename Enable = void>
1700 : struct is_trivially_destructible
1701 : : std::false_type
1702 : { };
1703 :
1704 : template <typename V>
1705 : struct is_trivially_destructible<V, typename std::enable_if<is_complete<V>::value>::type>
1706 : : std::is_trivially_destructible<V>
1707 : { };
1708 :
1709 : template <typename Void, typename T, typename ...Args>
1710 : struct is_trivially_constructible_impl
1711 : : std::false_type
1712 : { };
1713 :
1714 : template <typename V, typename ...Args>
1715 : struct is_trivially_constructible_impl<
1716 : typename std::enable_if<is_complete<V>::value>::type,
1717 : V, Args...>
1718 : : std::is_trivially_constructible<V, Args...>
1719 : { };
1720 :
1721 : template <typename V, typename ...Args>
1722 : struct is_trivially_constructible
1723 : : is_trivially_constructible_impl<void, V, Args...>
1724 : { };
1725 :
1726 : template <typename T, typename Enable = void>
1727 : struct underlying_if_enum
1728 : {
1729 : using type = T;
1730 : };
1731 :
1732 : template <typename T>
1733 : struct underlying_if_enum<T, typename std::enable_if<std::is_enum<T>::value>::type>
1734 : : std::underlying_type<T>
1735 : { };
1736 :
1737 : template <typename T>
1738 : using underlying_if_enum_t = typename underlying_if_enum<T>::type;
1739 :
1740 : template <typename, typename = void>
1741 : struct has_ptr_traits_to_address
1742 : : std::false_type
1743 : { };
1744 :
1745 : template <typename P>
1746 : struct has_ptr_traits_to_address<P,
1747 : void_t<decltype (std::pointer_traits<P>::to_address (std::declval<P> ()))>>
1748 : : std::true_type
1749 : { };
1750 :
1751 : template <typename Void, typename A, typename V, typename ...Args>
1752 : struct has_alloc_construct_check
1753 : : std::false_type
1754 : { };
1755 :
1756 : template <typename A, typename V, typename ...Args>
1757 : struct has_alloc_construct_check<
1758 : void_t<decltype (std::declval<A&> ().construct (std::declval<V *> (),
1759 : std::declval<Args> ()...))>,
1760 : A, V, Args...>
1761 : : std::true_type
1762 : { };
1763 :
1764 : template <typename Void, typename A, typename V, typename ...Args>
1765 : struct has_alloc_construct_impl
1766 : : std::false_type
1767 : { };
1768 :
1769 : template <typename A, typename V, typename ...Args>
1770 : struct has_alloc_construct_impl<typename std::enable_if<is_complete<V>::value>::type,
1771 : A, V, Args...>
1772 : : has_alloc_construct_check<void, A, V, Args...>
1773 : { };
1774 :
1775 : template <typename A, typename V, typename ...Args>
1776 : struct has_alloc_construct
1777 : : has_alloc_construct_impl<void, A, V, Args...>
1778 : { };
1779 :
1780 : template <typename A, typename V, typename ...Args>
1781 : struct must_use_alloc_construct
1782 : : bool_constant<! std::is_same<A, std::allocator<V>>::value
1783 : && has_alloc_construct<A, V, Args...>::value>
1784 : { };
1785 :
1786 : template <typename Void, typename A, typename V>
1787 : struct has_alloc_destroy_impl
1788 : : std::false_type
1789 : { };
1790 :
1791 : template <typename A, typename V>
1792 : struct has_alloc_destroy_impl<
1793 : void_t<decltype (std::declval<A&> ().destroy (std::declval<V *> ()))>,
1794 : A, V>
1795 : : std::true_type
1796 : { };
1797 :
1798 : template <typename A, typename V, typename Enable = void>
1799 : struct has_alloc_destroy
1800 : : std::false_type
1801 : { };
1802 :
1803 : template <typename A, typename V>
1804 : struct has_alloc_destroy<A, V, typename std::enable_if<is_complete<V>::value>::type>
1805 : : has_alloc_destroy_impl<void, A, V>
1806 : { };
1807 :
1808 : template <typename A, typename V>
1809 : struct must_use_alloc_destroy
1810 : : bool_constant<! std::is_same<A, std::allocator<V>>::value
1811 : && has_alloc_destroy<A, V>::value>
1812 : { };
1813 :
1814 : public:
1815 : allocator_interface (void) = default;
1816 : // allocator_interface (const allocator_interface&) = impl;
1817 : allocator_interface (allocator_interface&&) noexcept = default;
1818 :
1819 : PLUMED_GCH_CPP20_CONSTEXPR
1820 : allocator_interface&
1821 : operator= (const allocator_interface&) = default;
1822 :
1823 : PLUMED_GCH_CPP20_CONSTEXPR
1824 : allocator_interface&
1825 : operator= (allocator_interface&&) noexcept = default;
1826 :
1827 : ~allocator_interface (void) = default;
1828 :
1829 : PLUMED_GCH_CPP20_CONSTEXPR
1830 : allocator_interface (const allocator_interface& other) noexcept
1831 : : alloc_base (alloc_traits::select_on_container_copy_construction (other.allocator_ref ()))
1832 : { }
1833 :
1834 : constexpr explicit
1835 : allocator_interface (const alloc_ty& alloc) noexcept
1836 : : alloc_base (alloc)
1837 : { }
1838 :
1839 : template <typename T>
1840 : constexpr explicit
1841 : allocator_interface (T&&, const alloc_ty& alloc) noexcept
1842 : : allocator_interface (alloc)
1843 : { }
1844 :
1845 : template <typename, typename, typename = void>
1846 : struct is_memcpyable_integral
1847 : : std::false_type
1848 : { };
1849 :
1850 : template <typename From, typename To>
1851 : struct is_memcpyable_integral<From, To,
1852 : typename std::enable_if<is_complete<From>::value>::type>
1853 : {
1854 : using from = underlying_if_enum_t<From>;
1855 : using to = underlying_if_enum_t<To>;
1856 :
1857 : static constexpr
1858 : bool
1859 : value = (sizeof (from) == sizeof (to))
1860 : && (std::is_same<bool, from>::value == std::is_same<bool, to>::value)
1861 : && std::is_integral<from>::value
1862 : && std::is_integral<to>::value;
1863 : };
1864 :
1865 : template <typename From, typename To>
1866 : struct is_convertible_pointer
1867 : : bool_constant<std::is_pointer<From>::value
1868 : && std::is_pointer<To>::value
1869 : && std::is_convertible<From, To>::value>
1870 : { };
1871 :
1872 : // Memcpyable assignment.
1873 : template <typename QualifiedFrom, typename QualifiedTo = value_ty, typename Enable = void>
1874 : struct is_memcpyable
1875 : : std::false_type
1876 : { };
1877 :
1878 : template <typename QualifiedFrom, typename QualifiedTo>
1879 : struct is_memcpyable<QualifiedFrom, QualifiedTo,
1880 : typename std::enable_if<is_complete<QualifiedFrom>::value>::type>
1881 : {
1882 : static_assert (! std::is_reference<QualifiedTo>::value,
1883 : "QualifiedTo must not be a reference.");
1884 :
1885 : using from = typename std::remove_reference<
1886 : typename std::remove_cv<QualifiedFrom>::type>::type;
1887 :
1888 : using to = typename std::remove_cv<QualifiedTo>::type;
1889 :
1890 : static constexpr
1891 : bool
1892 : value = std::is_trivially_assignable<QualifiedTo&, QualifiedFrom>::value
1893 : && std::is_trivially_copyable<to>::value
1894 : && ( std::is_same<typename std::remove_cv<from>::type, to>::value
1895 : || is_memcpyable_integral<from, to>::value
1896 : || is_convertible_pointer<from, to>::value);
1897 : };
1898 :
1899 : // Memcpyable construction.
1900 : template <typename QualifiedFrom, typename QualifiedTo>
1901 : struct is_uninitialized_memcpyable_impl
1902 : {
1903 : static_assert (! std::is_reference<QualifiedTo>::value,
1904 : "QualifiedTo must not be a reference.");
1905 :
1906 : using from = typename std::remove_reference<
1907 : typename std::remove_cv<QualifiedFrom>::type>::type;
1908 :
1909 : using to = typename std::remove_cv<QualifiedTo>::type;
1910 :
1911 : static constexpr
1912 : bool
1913 : value = std::is_trivially_constructible<QualifiedTo, QualifiedFrom>::value
1914 : && std::is_trivially_copyable<to>::value
1915 : && ( std::is_same<typename std::remove_cv<from>::type, to>::value
1916 : || is_memcpyable_integral<from, to>::value
1917 : || is_convertible_pointer<from, to>::value)
1918 : && (! must_use_alloc_construct<alloc_ty, value_ty, from>::value
1919 : &&! must_use_alloc_destroy<alloc_ty, value_ty>::value);
1920 : };
1921 :
1922 : template <typename To, typename ...Args>
1923 : struct is_uninitialized_memcpyable
1924 : : std::false_type
1925 : { };
1926 :
1927 : template <typename To, typename From>
1928 : struct is_uninitialized_memcpyable<To, From>
1929 : : is_uninitialized_memcpyable_impl<From, To>
1930 : { };
1931 :
1932 : template <typename Iterator>
1933 : struct is_small_vector_iterator
1934 : : std::false_type
1935 : { };
1936 :
1937 : template <typename ...Ts>
1938 : struct is_small_vector_iterator<small_vector_iterator<Ts...>>
1939 : : std::true_type
1940 : { };
1941 :
1942 : template <typename InputIt>
1943 : struct is_contiguous_iterator
1944 : : bool_constant<
1945 : std::is_same<InputIt, ptr>::value
1946 : || std::is_same<InputIt, cptr>::value
1947 : || is_small_vector_iterator<InputIt>::value
1948 : #ifdef PLUMED_GCH_LIB_CONCEPTS
1949 : || std::contiguous_iterator<InputIt>
1950 : #endif
1951 : #ifdef PLUMED_GCH_STDLIB_INTEROP
1952 : || std::is_same<InputIt, typename std::array<value_ty>::iterator>::value
1953 : || std::is_same<InputIt, typename std::array<value_ty>::const_iterator>::value
1954 : || (! std::is_same<value_ty, bool>
1955 : && ( std::is_same<InputIt, typename std::vector<value_ty>::iterator>::value
1956 : || std::is_same<InputIt, typename std::vector<value_ty>::const_iterator>::value)
1957 : )
1958 : || std::is_same<InputIt,
1959 : decltype (std::begin (std::declval<std::valarray<value_ty>&> ()))>::value
1960 : || std::is_same<InputIt,
1961 : decltype (std::begin (std::declval<const std::valarray<value_ty>&> ()))>::value
1962 : #endif
1963 : >
1964 : { };
1965 :
1966 : template <typename InputIt>
1967 : struct is_memcpyable_iterator
1968 : : bool_constant<is_memcpyable<decltype (*std::declval<InputIt> ())>::value
1969 : && is_contiguous_iterator<InputIt>::value>
1970 : { };
1971 :
1972 : // Unwrap `move_iterator`s.
1973 : template <typename InputIt>
1974 : struct is_memcpyable_iterator<std::move_iterator<InputIt>>
1975 : : is_memcpyable_iterator<InputIt>
1976 : { };
1977 :
1978 : template <typename InputIt, typename V = value_ty>
1979 : struct is_uninitialized_memcpyable_iterator
1980 : : bool_constant<is_uninitialized_memcpyable<V, decltype (*std::declval<InputIt> ())>::value
1981 : && is_contiguous_iterator<InputIt>::value>
1982 : { };
1983 :
1984 : // unwrap move_iterators
1985 : template <typename U, typename V>
1986 : struct is_uninitialized_memcpyable_iterator<std::move_iterator<U>, V>
1987 : : is_uninitialized_memcpyable_iterator<U, V>
1988 : { };
1989 :
1990 : PLUMED_GCH_NORETURN
1991 : static PLUMED_GCH_CPP20_CONSTEXPR
1992 : void
1993 : throw_range_length_error (void)
1994 : {
1995 : #ifdef PLUMED_GCH_EXCEPTIONS
1996 : throw std::length_error ("The specified range is too long.");
1997 : #else
1998 : std::fprintf (stderr, "[gch::small_vector] The specified range is too long.");
1999 : std::abort ();
2000 : #endif
2001 : }
2002 :
2003 : static constexpr
2004 : value_ty *
2005 : to_address (value_ty *p) noexcept
2006 : {
2007 : static_assert (! std::is_function<value_ty>::value, "value_ty is a function pointer.");
2008 : return p;
2009 : }
2010 :
2011 : static constexpr
2012 : const value_ty *
2013 : to_address (const value_ty *p) noexcept
2014 : {
2015 : static_assert (! std::is_function<value_ty>::value, "value_ty is a function pointer.");
2016 : return p;
2017 : }
2018 :
2019 : template <typename Pointer,
2020 : typename std::enable_if<has_ptr_traits_to_address<Pointer>::value>::type * = nullptr>
2021 : static constexpr
2022 : auto
2023 : to_address (const Pointer& p) noexcept
2024 : -> decltype (std::pointer_traits<Pointer>::to_address (p))
2025 : {
2026 : return std::pointer_traits<Pointer>::to_address (p);
2027 : }
2028 :
2029 : template <typename Pointer,
2030 : typename std::enable_if<! has_ptr_traits_to_address<Pointer>::value>::type * = nullptr>
2031 : static constexpr
2032 : auto
2033 : to_address (const Pointer& p) noexcept
2034 : -> decltype (to_address (p.operator-> ()))
2035 : {
2036 : return to_address (p.operator-> ());
2037 : }
2038 :
2039 : template <typename Integer>
2040 : PLUMED_GCH_NODISCARD
2041 : static PLUMED_GCH_CONSTEVAL
2042 : std::size_t
2043 : numeric_max (void) noexcept
2044 : {
2045 : static_assert (0 <= (std::numeric_limits<Integer>::max) (), "Integer is nonpositive.");
2046 : return static_cast<std::size_t> ((std::numeric_limits<Integer>::max) ());
2047 : }
2048 :
2049 : PLUMED_GCH_NODISCARD
2050 : static PLUMED_GCH_CPP17_CONSTEXPR
2051 : size_ty
2052 : internal_range_length (cptr first, cptr last) noexcept
2053 : {
2054 : // This is guaranteed to be less than or equal to max size_ty.
2055 : return static_cast<size_ty> (last - first);
2056 : }
2057 :
2058 : template <typename RandomIt>
2059 : PLUMED_GCH_NODISCARD
2060 : static PLUMED_GCH_CPP17_CONSTEXPR
2061 : size_ty
2062 : external_range_length_impl (RandomIt first, RandomIt last, std::random_access_iterator_tag)
2063 : {
2064 : assert (0 <= (last - first) && "Invalid range.");
2065 : const auto len = static_cast<std::size_t> (last - first);
2066 : #ifndef NDEBUG
2067 : if (numeric_max<size_ty> () < len)
2068 : throw_range_length_error ();
2069 : #endif
2070 : return static_cast<size_ty> (len);
2071 : }
2072 :
2073 : template <typename ForwardIt>
2074 : PLUMED_GCH_NODISCARD
2075 : static PLUMED_GCH_CPP17_CONSTEXPR
2076 : size_ty
2077 : external_range_length_impl (ForwardIt first, ForwardIt last, std::forward_iterator_tag)
2078 : {
2079 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
2080 : if (std::is_constant_evaluated ())
2081 : {
2082 : // Make sure constexpr doesn't get broken by `using namespace std::rel_ops`.
2083 : typename std::iterator_traits<ForwardIt>::difference_type len = 0;
2084 : for (; ! (first == last); ++first)
2085 : ++len;
2086 : assert (static_cast<std::size_t> (len) <= numeric_max<size_ty> ());
2087 : return static_cast<size_ty> (len);
2088 : }
2089 : #endif
2090 :
2091 : const auto len = static_cast<std::size_t> (std::distance (first, last));
2092 : #ifndef NDEBUG
2093 : if (numeric_max<size_ty> () < len)
2094 : throw_range_length_error ();
2095 : #endif
2096 : return static_cast<size_ty> (len);
2097 : }
2098 :
2099 : template <typename ForwardIt,
2100 : typename ItDiffT = typename std::iterator_traits<ForwardIt>::difference_type,
2101 : typename std::enable_if<(numeric_max<size_ty> () < numeric_max<ItDiffT> ()),
2102 : bool>::type = true>
2103 : PLUMED_GCH_NODISCARD
2104 : static PLUMED_GCH_CPP17_CONSTEXPR
2105 : size_ty
2106 : external_range_length (ForwardIt first, ForwardIt last)
2107 : {
2108 : using iterator_cat = typename std::iterator_traits<ForwardIt>::iterator_category;
2109 : return external_range_length_impl (first, last, iterator_cat { });
2110 : }
2111 :
2112 : template <typename ForwardIt,
2113 : typename ItDiffT = typename std::iterator_traits<ForwardIt>::difference_type,
2114 : typename std::enable_if<! (numeric_max<size_ty> () < numeric_max<ItDiffT> ()),
2115 : bool>::type = false>
2116 : PLUMED_GCH_NODISCARD
2117 : static PLUMED_GCH_CPP17_CONSTEXPR
2118 : size_ty
2119 : external_range_length (ForwardIt first, ForwardIt last) noexcept
2120 : {
2121 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
2122 : if (std::is_constant_evaluated ())
2123 : {
2124 : // Make sure constexpr doesn't get broken by `using namespace std::rel_ops`.
2125 : size_ty len = 0;
2126 : for (; ! (first == last); ++first)
2127 : ++len;
2128 : return len;
2129 : }
2130 : #endif
2131 :
2132 24025 : return static_cast<size_ty> (std::distance (first, last));
2133 : }
2134 :
2135 : template <typename Iterator,
2136 : typename IteratorDiffT = typename std::iterator_traits<Iterator>::difference_type,
2137 : typename Integer = IteratorDiffT>
2138 : PLUMED_GCH_NODISCARD
2139 : static PLUMED_GCH_CPP17_CONSTEXPR
2140 : Iterator
2141 : unchecked_next (Iterator pos, Integer n = 1) noexcept
2142 : {
2143 20969311 : unchecked_advance (pos, static_cast<IteratorDiffT> (n));
2144 20993336 : return pos;
2145 : }
2146 :
2147 : template <typename Iterator,
2148 : typename IteratorDiffT = typename std::iterator_traits<Iterator>::difference_type,
2149 : typename Integer = IteratorDiffT>
2150 : PLUMED_GCH_NODISCARD
2151 : static PLUMED_GCH_CPP17_CONSTEXPR
2152 : Iterator
2153 : unchecked_prev (Iterator pos, Integer n = 1) noexcept
2154 : {
2155 : unchecked_advance (pos, -static_cast<IteratorDiffT> (n));
2156 2149600 : return pos;
2157 : }
2158 :
2159 : template <typename Iterator,
2160 : typename IteratorDiffT = typename std::iterator_traits<Iterator>::difference_type,
2161 : typename Integer = IteratorDiffT>
2162 : static PLUMED_GCH_CPP17_CONSTEXPR
2163 : void
2164 : unchecked_advance (Iterator& pos, Integer n) noexcept
2165 : {
2166 : std::advance (pos, static_cast<IteratorDiffT> (n));
2167 : }
2168 :
2169 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2170 : size_ty
2171 : get_max_size (void) const noexcept
2172 : {
2173 : // This is protected from max/min macros.
2174 : return (std::min) (static_cast<size_ty> (alloc_traits::max_size (allocator_ref ())),
2175 : static_cast<size_ty> (numeric_max<difference_type> ()));
2176 : }
2177 :
2178 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2179 : ptr
2180 : allocate (size_ty n)
2181 : {
2182 : return alloc_traits::allocate (allocator_ref (), static_cast<size_type> (n));
2183 : }
2184 :
2185 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2186 : ptr
2187 : allocate_with_hint (size_ty n, cptr hint)
2188 : {
2189 : return alloc_traits::allocate (allocator_ref (), static_cast<size_type> (n), hint);
2190 : }
2191 :
2192 : PLUMED_GCH_CPP20_CONSTEXPR
2193 : void
2194 : deallocate (ptr p, size_ty n)
2195 : {
2196 : alloc_traits::deallocate (allocator_ref (), to_address (p),
2197 : static_cast<size_type> (n));
2198 3657 : }
2199 :
2200 : template <typename U,
2201 : typename std::enable_if<
2202 : is_uninitialized_memcpyable<value_ty, U>::value>::type * = nullptr>
2203 : PLUMED_GCH_CPP20_CONSTEXPR
2204 : void
2205 : construct (ptr p, U&& val) noexcept
2206 : {
2207 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
2208 : if (std::is_constant_evaluated ())
2209 : {
2210 : alloc_traits::construct (allocator_ref (), to_address (p), std::forward<U> (val));
2211 : return;
2212 : }
2213 : #endif
2214 : std::memcpy (to_address (p), &val, sizeof (value_ty));
2215 : }
2216 :
2217 : // basically alloc_traits::construct
2218 : // all this is so we can replicate C++20 behavior in the other overload
2219 : template <typename A = alloc_ty, typename V = value_ty, typename ...Args,
2220 : typename std::enable_if<( sizeof...(Args) != 1
2221 : ||! is_uninitialized_memcpyable<V, Args...>::value)
2222 : && has_alloc_construct<A, V, Args...>::value>::type * = nullptr>
2223 : PLUMED_GCH_CPP20_CONSTEXPR
2224 : void
2225 : construct (ptr p, Args&&... args)
2226 : noexcept (noexcept (alloc_traits::construct (std::declval<alloc_ty&> (),
2227 : std::declval<value_ty *> (),
2228 : std::forward<Args> (args)...)))
2229 : {
2230 : alloc_traits::construct (allocator_ref (), to_address (p), std::forward<Args> (args)...);
2231 : }
2232 :
2233 : template <typename A = alloc_ty, typename V = value_ty, typename ...Args,
2234 : void_t<typename std::enable_if<( sizeof...(Args) != 1
2235 : ||! is_uninitialized_memcpyable<V, Args...>::value)
2236 : &&! has_alloc_construct<A, V, Args...>::value>::type,
2237 : decltype (::new (std::declval<void *> ()) V (std::declval<Args> ()...))
2238 : > * = nullptr>
2239 : PLUMED_GCH_CPP20_CONSTEXPR
2240 : void
2241 : construct (ptr p, Args&&... args)
2242 : noexcept (noexcept (::new (std::declval<void *> ()) value_ty (std::declval<Args> ()...)))
2243 : {
2244 : construct_at (to_address (p), std::forward<Args> (args)...);
2245 : }
2246 :
2247 : template <typename A = alloc_ty, typename V = value_ty,
2248 : typename std::enable_if<is_trivially_destructible<V>::value
2249 : &&! must_use_alloc_destroy<A, V>::value>::type * = nullptr>
2250 : PLUMED_GCH_CPP20_CONSTEXPR
2251 : void
2252 : destroy (ptr) const noexcept
2253 : { }
2254 :
2255 : template <typename A = alloc_ty, typename V = value_ty,
2256 : typename std::enable_if<(! is_trivially_destructible<V>::value
2257 : || must_use_alloc_destroy<A, V>::value)
2258 : && has_alloc_destroy<A, V>::value>::type * = nullptr>
2259 : PLUMED_GCH_CPP20_CONSTEXPR
2260 : void
2261 : destroy (ptr p) noexcept
2262 : {
2263 : alloc_traits::destroy (allocator_ref (), to_address (p));
2264 : }
2265 :
2266 : // defined so we match C++20 behavior in all cases.
2267 : template <typename A = alloc_ty, typename V = value_ty,
2268 : typename std::enable_if<(! is_trivially_destructible<V>::value
2269 : || must_use_alloc_destroy<A, V>::value)
2270 : &&! has_alloc_destroy<A, V>::value>::type * = nullptr>
2271 : PLUMED_GCH_CPP20_CONSTEXPR
2272 : void
2273 : destroy (ptr p) noexcept
2274 : {
2275 : destroy_at (to_address (p));
2276 : }
2277 :
2278 : template <typename A = alloc_ty, typename V = value_ty,
2279 : typename std::enable_if<is_trivially_destructible<V>::value
2280 : &&! must_use_alloc_destroy<A, V>::value>::type * = nullptr>
2281 : PLUMED_GCH_CPP14_CONSTEXPR
2282 : void
2283 : destroy_range (ptr, ptr) const noexcept
2284 : { }
2285 :
2286 : template <typename A = alloc_ty, typename V = value_ty,
2287 : typename std::enable_if<! is_trivially_destructible<V>::value
2288 : || must_use_alloc_destroy<A, V>::value>::type * = nullptr>
2289 : PLUMED_GCH_CPP20_CONSTEXPR
2290 : void
2291 : destroy_range (ptr first, ptr last) noexcept
2292 : {
2293 : for (; ! (first == last); ++first)
2294 : destroy (first);
2295 : }
2296 :
2297 : // allowed if trivially copyable and we use the standard allocator
2298 : // and InputIt is a contiguous iterator
2299 : template <typename ForwardIt,
2300 : typename std::enable_if<
2301 : is_uninitialized_memcpyable_iterator<ForwardIt>::value, bool>::type = true>
2302 : PLUMED_GCH_CPP20_CONSTEXPR
2303 : ptr
2304 24025 : uninitialized_copy (ForwardIt first, ForwardIt last, ptr dest) noexcept
2305 : {
2306 : static_assert (std::is_constructible<value_ty, decltype (*first)>::value,
2307 : "`value_type` must be copy constructible.");
2308 :
2309 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
2310 : if (std::is_constant_evaluated ())
2311 : return default_uninitialized_copy (first, last, dest);
2312 : #endif
2313 :
2314 : const size_ty num_copy = external_range_length (first, last);
2315 24025 : if (num_copy != 0)
2316 21681 : std::memcpy (to_address (dest), to_address (first), num_copy * sizeof (value_ty));
2317 24025 : return unchecked_next (dest, num_copy);
2318 : }
2319 :
2320 : template <typename ForwardIt,
2321 : typename std::enable_if<
2322 : is_uninitialized_memcpyable_iterator<ForwardIt>::value, bool>::type = true>
2323 : PLUMED_GCH_CPP20_CONSTEXPR
2324 : ptr
2325 : uninitialized_copy (std::move_iterator<ForwardIt> first,
2326 : std::move_iterator<ForwardIt> last,
2327 : ptr dest) noexcept
2328 : {
2329 3657 : return uninitialized_copy (first.base (), last.base (), dest);
2330 : }
2331 :
2332 : template <typename InputIt,
2333 : typename std::enable_if<
2334 : ! is_uninitialized_memcpyable_iterator<InputIt>::value, bool>::type = false>
2335 : PLUMED_GCH_CPP20_CONSTEXPR
2336 : ptr
2337 : uninitialized_copy (InputIt first, InputIt last, ptr d_first)
2338 : {
2339 : return default_uninitialized_copy (first, last, d_first);
2340 : }
2341 :
2342 : template <typename InputIt>
2343 : PLUMED_GCH_CPP20_CONSTEXPR
2344 : ptr
2345 : default_uninitialized_copy (InputIt first, InputIt last, ptr d_first)
2346 : {
2347 : ptr d_last = d_first;
2348 : PLUMED_GCH_TRY
2349 : {
2350 : // Note: Not != because `using namespace std::rel_ops` can break constexpr.
2351 : for (; ! (first == last); ++first, static_cast<void> (++d_last))
2352 : construct (d_last, *first);
2353 : return d_last;
2354 : }
2355 : PLUMED_GCH_CATCH (...)
2356 : {
2357 : destroy_range (d_first, d_last);
2358 : PLUMED_GCH_THROW;
2359 : }
2360 : }
2361 :
2362 : template <typename A = alloc_ty, typename V = value_ty,
2363 : typename std::enable_if<is_trivially_constructible<V>::value
2364 : &&! must_use_alloc_construct<A, V>::value>::type * = nullptr>
2365 : PLUMED_GCH_CPP20_CONSTEXPR
2366 : ptr
2367 : uninitialized_value_construct (ptr first, ptr last)
2368 : {
2369 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
2370 : if (std::is_constant_evaluated ())
2371 : return default_uninitialized_value_construct (first, last);
2372 : #endif
2373 : std::fill (first, last, value_ty ());
2374 : return last;
2375 : }
2376 :
2377 : template <typename A = alloc_ty, typename V = value_ty,
2378 : typename std::enable_if<! is_trivially_constructible<V>::value
2379 : || must_use_alloc_construct<A, V>::value>::type * = nullptr>
2380 : PLUMED_GCH_CPP20_CONSTEXPR
2381 : ptr
2382 : uninitialized_value_construct (ptr first, ptr last)
2383 : {
2384 : return default_uninitialized_value_construct (first, last);
2385 : }
2386 :
2387 : PLUMED_GCH_CPP20_CONSTEXPR
2388 : ptr
2389 : default_uninitialized_value_construct (ptr first, ptr last)
2390 : {
2391 : ptr curr = first;
2392 : PLUMED_GCH_TRY
2393 : {
2394 : for (; ! (curr == last); ++curr)
2395 : construct (curr);
2396 : return curr;
2397 : }
2398 : PLUMED_GCH_CATCH (...)
2399 : {
2400 : destroy_range (first, curr);
2401 : PLUMED_GCH_THROW;
2402 : }
2403 : }
2404 :
2405 : PLUMED_GCH_CPP20_CONSTEXPR
2406 : ptr
2407 : uninitialized_fill (ptr first, ptr last)
2408 : {
2409 : return uninitialized_value_construct (first, last);
2410 : }
2411 :
2412 : PLUMED_GCH_CPP20_CONSTEXPR
2413 : ptr
2414 : uninitialized_fill (ptr first, ptr last, const value_ty& val)
2415 : {
2416 : ptr curr = first;
2417 : PLUMED_GCH_TRY
2418 : {
2419 : for (; ! (curr == last); ++curr)
2420 : construct (curr, val);
2421 : return curr;
2422 : }
2423 : PLUMED_GCH_CATCH (...)
2424 : {
2425 : destroy_range (first, curr);
2426 : PLUMED_GCH_THROW;
2427 : }
2428 : }
2429 :
2430 : private:
2431 : // If value_ty is an array, replicate C++20 behavior (I don't think that value_ty can
2432 : // actually be an array because of the Erasable requirement, but there shouldn't
2433 : // be any runtime cost for being defensive here).
2434 : template <typename V = value_ty,
2435 : typename std::enable_if<std::is_array<V>::value, bool>::type = true>
2436 : static PLUMED_GCH_CPP20_CONSTEXPR
2437 : void
2438 : destroy_at (value_ty *p) noexcept
2439 : {
2440 : for (auto& e : *p)
2441 : destroy_at (std::addressof (e));
2442 : }
2443 :
2444 : template <typename V = value_ty,
2445 : typename std::enable_if<! std::is_array<V>::value, bool>::type = false>
2446 : static PLUMED_GCH_CPP20_CONSTEXPR
2447 : void
2448 : destroy_at (value_ty *p) noexcept
2449 : {
2450 : p->~value_ty ();
2451 : }
2452 :
2453 : template <typename V = value_ty, typename ...Args>
2454 : static PLUMED_GCH_CPP20_CONSTEXPR
2455 : auto
2456 : construct_at (value_ty *p, Args&&... args)
2457 : noexcept (noexcept (::new (std::declval<void *> ()) V (std::declval<Args> ()...)))
2458 : -> decltype (::new (std::declval<void *> ()) V (std::declval<Args> ()...))
2459 : {
2460 : #if defined (PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED) && defined (PLUMED_GCH_LIB_CONSTEXPR_MEMORY)
2461 : if (std::is_constant_evaluated ())
2462 : return std::construct_at (p, std::forward<Args> (args)...);
2463 : #endif
2464 : void *vp = const_cast<void *> (static_cast<const volatile void *> (p));
2465 : return ::new (vp) value_ty (std::forward<Args>(args)...);
2466 : }
2467 : };
2468 :
2469 : template <typename Pointer, typename SizeT>
2470 : class small_vector_data_base
2471 : {
2472 : public:
2473 : using ptr = Pointer;
2474 : using size_ty = SizeT;
2475 :
2476 : small_vector_data_base (void) = default;
2477 : small_vector_data_base (const small_vector_data_base&) = default;
2478 : small_vector_data_base (small_vector_data_base&&) noexcept = default;
2479 : small_vector_data_base& operator= (const small_vector_data_base&) = default;
2480 : small_vector_data_base& operator= (small_vector_data_base&&) noexcept = default;
2481 : ~small_vector_data_base (void) = default;
2482 :
2483 150088598 : constexpr ptr data_ptr (void) const noexcept { return m_data_ptr; }
2484 8031995 : constexpr size_ty capacity (void) const noexcept { return m_capacity; }
2485 183442755 : constexpr size_ty size (void) const noexcept { return m_size; }
2486 :
2487 1639830 : PLUMED_GCH_CPP20_CONSTEXPR void set_data_ptr (ptr data_ptr) noexcept { m_data_ptr = data_ptr; }
2488 1639830 : PLUMED_GCH_CPP20_CONSTEXPR void set_capacity (size_ty capacity) noexcept { m_capacity = capacity; }
2489 7559839 : PLUMED_GCH_CPP20_CONSTEXPR void set_size (size_ty size) noexcept { m_size = size; }
2490 :
2491 : PLUMED_GCH_CPP20_CONSTEXPR
2492 : void
2493 : set (ptr data_ptr, size_ty capacity, size_ty size)
2494 : {
2495 1313 : m_data_ptr = data_ptr;
2496 1313 : m_capacity = capacity;
2497 1313 : m_size = size;
2498 : }
2499 :
2500 : PLUMED_GCH_CPP20_CONSTEXPR
2501 : void
2502 : swap_data_ptr (small_vector_data_base& other) noexcept
2503 : {
2504 : using std::swap;
2505 : swap (m_data_ptr, other.m_data_ptr);
2506 : }
2507 :
2508 : PLUMED_GCH_CPP20_CONSTEXPR
2509 : void
2510 : swap_capacity (small_vector_data_base& other) noexcept
2511 : {
2512 : using std::swap;
2513 : swap (m_capacity, other.m_capacity);
2514 : }
2515 :
2516 : PLUMED_GCH_CPP20_CONSTEXPR
2517 : void
2518 : swap_size (small_vector_data_base& other) noexcept
2519 : {
2520 : using std::swap;
2521 : swap (m_size, other.m_size);
2522 : }
2523 :
2524 : PLUMED_GCH_CPP20_CONSTEXPR
2525 : void
2526 : swap (small_vector_data_base& other) noexcept
2527 : {
2528 : using std::swap;
2529 : swap (m_data_ptr, other.m_data_ptr);
2530 : swap (m_capacity, other.m_capacity);
2531 : swap (m_size, other.m_size);
2532 : }
2533 :
2534 : private:
2535 : ptr m_data_ptr;
2536 : size_ty m_capacity;
2537 : size_ty m_size;
2538 : };
2539 :
2540 : template <typename Pointer, typename SizeT, typename T, unsigned InlineCapacity>
2541 : class small_vector_data
2542 : : public small_vector_data_base<Pointer, SizeT>
2543 : {
2544 : public:
2545 : using value_ty = T;
2546 :
2547 : small_vector_data (void) = default;
2548 : small_vector_data (const small_vector_data&) = delete;
2549 : small_vector_data (small_vector_data&&) noexcept = delete;
2550 : small_vector_data& operator= (const small_vector_data&) = delete;
2551 : small_vector_data& operator= (small_vector_data&&) noexcept = delete;
2552 : ~small_vector_data (void) = default;
2553 :
2554 : PLUMED_GCH_CPP14_CONSTEXPR
2555 : value_ty *
2556 : storage (void) noexcept
2557 : {
2558 : return m_storage.get_inline_ptr ();
2559 : }
2560 :
2561 : constexpr
2562 : const value_ty *
2563 : storage (void) const noexcept
2564 : {
2565 : return m_storage.get_inline_ptr ();
2566 : }
2567 :
2568 : private:
2569 : inline_storage<value_ty, InlineCapacity> m_storage;
2570 : };
2571 :
2572 : template <typename Pointer, typename SizeT, typename T>
2573 : class PLUMED_GCH_EMPTY_BASE small_vector_data<Pointer, SizeT, T, 0>
2574 : : public small_vector_data_base<Pointer, SizeT>,
2575 : private inline_storage<T, 0>
2576 : {
2577 : using base = inline_storage<T, 0>;
2578 :
2579 : public:
2580 : using value_ty = T;
2581 :
2582 : small_vector_data (void) = default;
2583 : small_vector_data (const small_vector_data&) = delete;
2584 : small_vector_data (small_vector_data&&) noexcept = delete;
2585 : small_vector_data& operator= (const small_vector_data&) = delete;
2586 : small_vector_data& operator= (small_vector_data&&) noexcept = delete;
2587 : ~small_vector_data (void) = default;
2588 :
2589 : PLUMED_GCH_CPP14_CONSTEXPR
2590 : value_ty *
2591 : storage (void) noexcept
2592 : {
2593 : return base::get_inline_ptr ();
2594 : }
2595 :
2596 : constexpr
2597 : const value_ty *
2598 : storage (void) const noexcept
2599 : {
2600 : return base::get_inline_ptr ();
2601 : }
2602 : };
2603 :
2604 : template <typename Allocator, unsigned InlineCapacity>
2605 : class small_vector_base
2606 : : public allocator_interface<Allocator>
2607 : {
2608 : public:
2609 : using size_type = typename allocator_interface<Allocator>::size_type;
2610 : using difference_type = typename allocator_interface<Allocator>::difference_type;
2611 :
2612 : template <typename SameAllocator, unsigned DifferentInlineCapacity>
2613 : friend class small_vector_base;
2614 :
2615 : protected:
2616 : using alloc_interface = allocator_interface<Allocator>;
2617 : using alloc_traits = typename alloc_interface::alloc_traits;
2618 : using alloc_ty = Allocator;
2619 :
2620 : using value_ty = typename alloc_interface::value_ty;
2621 : using ptr = typename alloc_interface::ptr;
2622 : using cptr = typename alloc_interface::cptr;
2623 : using size_ty = typename alloc_interface::size_ty;
2624 : using diff_ty = typename alloc_interface::diff_ty;
2625 :
2626 : static_assert (alloc_interface::template is_complete<value_ty>::value || InlineCapacity == 0,
2627 : "`value_type` must be complete for instantiation of a non-zero number "
2628 : "of inline elements.");
2629 :
2630 : template <typename T>
2631 : using is_complete = typename alloc_interface::template is_complete<T>;
2632 :
2633 : using alloc_interface::allocator_ref;
2634 : using alloc_interface::construct;
2635 : using alloc_interface::deallocate;
2636 : using alloc_interface::destroy;
2637 : using alloc_interface::destroy_range;
2638 : using alloc_interface::external_range_length;
2639 : using alloc_interface::get_max_size;
2640 : using alloc_interface::internal_range_length;
2641 : using alloc_interface::to_address;
2642 : using alloc_interface::unchecked_advance;
2643 : using alloc_interface::unchecked_next;
2644 : using alloc_interface::unchecked_prev;
2645 : using alloc_interface::uninitialized_copy;
2646 : using alloc_interface::uninitialized_fill;
2647 : using alloc_interface::uninitialized_value_construct;
2648 :
2649 : template <typename Integer>
2650 : PLUMED_GCH_NODISCARD
2651 : static PLUMED_GCH_CONSTEVAL
2652 : std::size_t
2653 : numeric_max (void) noexcept
2654 : {
2655 : return alloc_interface::template numeric_max<Integer> ();
2656 : }
2657 :
2658 : PLUMED_GCH_NODISCARD
2659 : static PLUMED_GCH_CONSTEVAL
2660 : size_ty
2661 : get_inline_capacity (void) noexcept
2662 : {
2663 : return static_cast<size_ty> (InlineCapacity);
2664 : }
2665 :
2666 : template <typename ...>
2667 : using void_t = void;
2668 :
2669 : template <bool B>
2670 : using bool_constant = std::integral_constant<bool, B>;
2671 :
2672 : template <typename Void, typename AI, typename V, typename ...Args>
2673 : struct is_emplace_constructible_impl
2674 : : std::false_type
2675 : {
2676 : using nothrow = std::false_type;
2677 : };
2678 :
2679 : template <typename AI, typename V, typename ...Args>
2680 : struct is_emplace_constructible_impl<
2681 : void_t<typename std::enable_if<is_complete<V>::value>::type,
2682 : decltype (std::declval<AI&> ().construct (std::declval<V *> (),
2683 : std::declval<Args> ()...))>,
2684 : AI, V, Args...>
2685 : : std::true_type
2686 : {
2687 : using nothrow =
2688 : bool_constant<noexcept (std::declval<AI&> ().construct (std::declval<V *> (),
2689 : std::declval<Args> ()...))>;
2690 : };
2691 :
2692 : template <typename ...Args>
2693 : struct is_emplace_constructible
2694 : : is_emplace_constructible_impl<void, alloc_interface, value_ty, Args...>
2695 : { };
2696 :
2697 : template <typename ...Args>
2698 : struct is_nothrow_emplace_constructible
2699 : : is_emplace_constructible_impl<void, alloc_interface, value_ty, Args...>::nothrow
2700 : { };
2701 :
2702 : template <typename V = value_ty>
2703 : struct is_explicitly_move_insertable
2704 : : is_emplace_constructible<V&&>
2705 : { };
2706 :
2707 : template <typename V = value_ty>
2708 : struct is_explicitly_nothrow_move_insertable
2709 : : is_nothrow_emplace_constructible<V&&>
2710 : { };
2711 :
2712 : template <typename V = value_ty>
2713 : struct is_explicitly_copy_insertable
2714 : : std::integral_constant<bool, is_emplace_constructible<V&>::value
2715 : && is_emplace_constructible<const V&>::value>
2716 : { };
2717 :
2718 : template <typename V = value_ty>
2719 : struct is_explicitly_nothrow_copy_insertable
2720 : : std::integral_constant<bool, is_nothrow_emplace_constructible<V&>::value
2721 : && is_nothrow_emplace_constructible<const V&>::value>
2722 : { };
2723 :
2724 : template <typename AI, typename Enable = void>
2725 : struct is_eraseable
2726 : : std::false_type
2727 : { };
2728 :
2729 : template <typename AI>
2730 : struct is_eraseable<AI,
2731 : void_t<decltype (std::declval<AI&> ().destroy (std::declval<value_ty *> ()))>>
2732 : : std::true_type
2733 : { };
2734 :
2735 : template <typename V>
2736 : struct relocate_with_move
2737 : #ifdef PLUMED_GCH_NO_STRONG_EXCEPTION_GUARANTEES
2738 : : std::true_type
2739 : #else
2740 : : bool_constant<std::is_nothrow_move_constructible<V>::value
2741 : ||! is_explicitly_copy_insertable<V>::value>
2742 : #endif
2743 : { };
2744 :
2745 : template <typename A>
2746 : struct allocations_are_movable
2747 : : bool_constant<std::is_same<std::allocator<value_ty>, A>::value
2748 : || std::allocator_traits<A>::propagate_on_container_move_assignment::value
2749 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
2750 : || std::allocator_traits<A>::is_always_equal::value
2751 : #endif
2752 : >
2753 : { };
2754 :
2755 : template <typename A>
2756 : struct allocations_are_swappable
2757 : : bool_constant<std::is_same<std::allocator<value_ty>, A>::value
2758 : || std::allocator_traits<A>::propagate_on_container_swap::value
2759 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
2760 : || std::allocator_traits<A>::is_always_equal::value
2761 : #endif
2762 : >
2763 : { };
2764 :
2765 : template <typename ...Args>
2766 : using is_memcpyable = typename alloc_interface::template is_memcpyable<Args...>;
2767 :
2768 : template <typename ...Args>
2769 : using is_memcpyable_iterator =
2770 : typename alloc_interface::template is_memcpyable_iterator<Args...>;
2771 :
2772 : PLUMED_GCH_NORETURN
2773 : static PLUMED_GCH_CPP20_CONSTEXPR
2774 : void
2775 : throw_overflow_error (void)
2776 : {
2777 : #ifdef PLUMED_GCH_EXCEPTIONS
2778 : throw std::overflow_error ("The requested conversion would overflow.");
2779 : #else
2780 : std::fprintf (stderr, "[gch::small_vector] The requested conversion would overflow.\n");
2781 : std::abort ();
2782 : #endif
2783 : }
2784 :
2785 : PLUMED_GCH_NORETURN
2786 : static PLUMED_GCH_CPP20_CONSTEXPR
2787 : void
2788 : throw_index_error (void)
2789 : {
2790 : #ifdef PLUMED_GCH_EXCEPTIONS
2791 : throw std::out_of_range ("The requested index was out of range.");
2792 : #else
2793 : std::fprintf (stderr, "[gch::small_vector] The requested index was out of range.\n");
2794 : std::abort ();
2795 : #endif
2796 : }
2797 :
2798 : PLUMED_GCH_NORETURN
2799 : static PLUMED_GCH_CPP20_CONSTEXPR
2800 : void
2801 : throw_increment_error (void)
2802 : {
2803 : #ifdef PLUMED_GCH_EXCEPTIONS
2804 : throw std::domain_error ("The requested increment was outside of the allowed range.");
2805 : #else
2806 : std::fprintf (
2807 : stderr,
2808 : "[gch::small_vector] The requested increment was outside of the allowed range.\n");
2809 : std::abort ();
2810 : #endif
2811 : }
2812 :
2813 : PLUMED_GCH_NORETURN
2814 : static PLUMED_GCH_CPP20_CONSTEXPR
2815 : void
2816 0 : throw_allocation_size_error (void)
2817 : {
2818 : #ifdef PLUMED_GCH_EXCEPTIONS
2819 0 : throw std::length_error ("The required allocation exceeds the maximum size.");
2820 : #else
2821 : std::fprintf (
2822 : stderr,
2823 : "[gch::small_vector] The required allocation exceeds the maximum size.\n");
2824 : std::abort ();
2825 : #endif
2826 : }
2827 :
2828 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
2829 : ptr
2830 : ptr_cast (const small_vector_iterator<cptr, diff_ty>& it) noexcept
2831 : {
2832 : return unchecked_next (begin_ptr (), it.base () - begin_ptr ());
2833 : }
2834 :
2835 : private:
2836 : class stack_temporary
2837 : {
2838 : public:
2839 : stack_temporary (void) = delete;
2840 : stack_temporary (const stack_temporary&) = delete;
2841 : stack_temporary (stack_temporary&&) noexcept = delete;
2842 : stack_temporary& operator= (const stack_temporary&) = delete;
2843 : stack_temporary& operator= (stack_temporary&&) noexcept = delete;
2844 : // ~stack_temporary (void) = impl;
2845 :
2846 : template <typename ...Args>
2847 : PLUMED_GCH_CPP20_CONSTEXPR explicit
2848 : stack_temporary (alloc_interface& alloc_iface, Args&&... args)
2849 : : m_interface (alloc_iface)
2850 : {
2851 : m_interface.construct (get_pointer (), std::forward<Args> (args)...);
2852 : }
2853 :
2854 : PLUMED_GCH_CPP20_CONSTEXPR
2855 : ~stack_temporary (void)
2856 : {
2857 : m_interface.destroy (get_pointer ());
2858 : }
2859 :
2860 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2861 : const value_ty&
2862 : get (void) const noexcept
2863 : {
2864 : return *get_pointer ();
2865 : }
2866 :
2867 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2868 : value_ty&&
2869 : release (void) noexcept
2870 : {
2871 : return std::move (*get_pointer ());
2872 : }
2873 :
2874 : private:
2875 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2876 : cptr
2877 : get_pointer (void) const noexcept
2878 : {
2879 : return static_cast<cptr> (static_cast<const void *> (std::addressof (m_data)));
2880 : }
2881 :
2882 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2883 : ptr
2884 : get_pointer (void) noexcept
2885 : {
2886 : return static_cast<ptr> (static_cast<void *> (std::addressof (m_data)));
2887 : }
2888 :
2889 : alloc_interface& m_interface;
2890 : typename std::aligned_storage<sizeof (value_ty), alignof (value_ty)>::type m_data;
2891 : };
2892 :
2893 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
2894 :
2895 : class heap_temporary
2896 : {
2897 : public:
2898 : heap_temporary (void) = delete;
2899 : heap_temporary (const heap_temporary&) = delete;
2900 : heap_temporary (heap_temporary&&) noexcept = delete;
2901 : heap_temporary& operator= (const heap_temporary&) = delete;
2902 : heap_temporary& operator= (heap_temporary&&) noexcept = delete;
2903 : // ~heap_temporary (void) = impl;
2904 :
2905 : template <typename ...Args>
2906 : PLUMED_GCH_CPP20_CONSTEXPR explicit
2907 : heap_temporary (alloc_interface& alloc_iface, Args&&... args)
2908 : : m_interface (alloc_iface),
2909 : m_data_ptr (alloc_iface.allocate (sizeof (value_ty)))
2910 : {
2911 : PLUMED_GCH_TRY
2912 : {
2913 : m_interface.construct (m_data_ptr, std::forward<Args> (args)...);
2914 : }
2915 : PLUMED_GCH_CATCH (...)
2916 : {
2917 : m_interface.deallocate (m_data_ptr, sizeof (value_ty));
2918 : PLUMED_GCH_THROW;
2919 : }
2920 : }
2921 :
2922 : PLUMED_GCH_CPP20_CONSTEXPR
2923 : ~heap_temporary (void)
2924 : {
2925 : m_interface.destroy (m_data_ptr);
2926 : m_interface.deallocate (m_data_ptr, sizeof (value_ty));
2927 : }
2928 :
2929 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2930 : const value_ty&
2931 : get (void) const noexcept
2932 : {
2933 : return *m_data_ptr;
2934 : }
2935 :
2936 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP20_CONSTEXPR
2937 : value_ty&&
2938 : release (void) noexcept
2939 : {
2940 : return std::move (*m_data_ptr);
2941 : }
2942 :
2943 : private:
2944 : alloc_interface& m_interface;
2945 : ptr m_data_ptr;
2946 : };
2947 :
2948 : #endif
2949 :
2950 : PLUMED_GCH_CPP20_CONSTEXPR
2951 : void
2952 1617101 : wipe (void)
2953 : {
2954 1617101 : destroy_range (begin_ptr (), end_ptr ());
2955 1617101 : if (has_allocation ())
2956 : deallocate (data_ptr (), get_capacity ());
2957 1617101 : }
2958 :
2959 : PLUMED_GCH_CPP20_CONSTEXPR
2960 : void
2961 : set_data_ptr (ptr data_ptr) noexcept
2962 : {
2963 : m_data.set_data_ptr (data_ptr);
2964 : }
2965 :
2966 : PLUMED_GCH_CPP20_CONSTEXPR
2967 : void
2968 : set_capacity (size_ty capacity) noexcept
2969 : {
2970 : m_data.set_capacity (static_cast<size_type> (capacity));
2971 2344 : }
2972 :
2973 : PLUMED_GCH_CPP20_CONSTEXPR
2974 : void
2975 : set_size (size_ty size) noexcept
2976 : {
2977 : m_data.set_size (static_cast<size_type> (size));
2978 4208848 : }
2979 :
2980 : PLUMED_GCH_CPP20_CONSTEXPR
2981 : void
2982 : set_data (ptr data_ptr, size_ty capacity, size_ty size) noexcept
2983 : {
2984 : m_data.set (data_ptr, static_cast<size_type> (capacity), static_cast<size_type> (size));
2985 : }
2986 :
2987 : PLUMED_GCH_CPP20_CONSTEXPR
2988 : void
2989 : swap_data_ptr (small_vector_base& other) noexcept
2990 : {
2991 : m_data.swap_data_ptr (other.m_data);
2992 : }
2993 :
2994 : PLUMED_GCH_CPP20_CONSTEXPR
2995 : void
2996 : swap_capacity (small_vector_base& other) noexcept
2997 : {
2998 : m_data.swap_capacity (other.m_data);
2999 : }
3000 :
3001 : PLUMED_GCH_CPP20_CONSTEXPR
3002 : void
3003 : swap_size (small_vector_base& other) noexcept
3004 : {
3005 : m_data.swap_size (other.m_data);
3006 : }
3007 :
3008 : PLUMED_GCH_CPP20_CONSTEXPR
3009 : void
3010 : swap_allocation (small_vector_base& other) noexcept
3011 : {
3012 : m_data.swap (other.m_data);
3013 : }
3014 :
3015 : PLUMED_GCH_CPP20_CONSTEXPR
3016 : void
3017 : reset_data (ptr data_ptr, size_ty capacity, size_ty size)
3018 : {
3019 1313 : wipe ();
3020 : m_data.set (data_ptr, static_cast<size_type> (capacity), static_cast<size_type> (size));
3021 0 : }
3022 :
3023 : PLUMED_GCH_CPP20_CONSTEXPR
3024 : void
3025 : increase_size (size_ty n) noexcept
3026 : {
3027 2149600 : m_data.set_size (get_size () + n);
3028 : }
3029 :
3030 : PLUMED_GCH_CPP20_CONSTEXPR
3031 : void
3032 : decrease_size (size_ty n) noexcept
3033 : {
3034 137267 : m_data.set_size (get_size () - n);
3035 : }
3036 :
3037 : PLUMED_GCH_CPP20_CONSTEXPR
3038 : ptr
3039 : unchecked_allocate (size_ty n)
3040 : {
3041 : assert (InlineCapacity < n && "Allocated capacity should be greater than InlineCapacity.");
3042 : return alloc_interface::allocate (n);
3043 : }
3044 :
3045 : PLUMED_GCH_CPP20_CONSTEXPR
3046 : ptr
3047 : unchecked_allocate (size_ty n, cptr hint)
3048 : {
3049 : assert (InlineCapacity < n && "Allocated capacity should be greater than InlineCapacity.");
3050 : return alloc_interface::allocate_with_hint (n, hint);
3051 : }
3052 :
3053 : PLUMED_GCH_CPP20_CONSTEXPR
3054 : ptr
3055 0 : checked_allocate (size_ty n)
3056 : {
3057 0 : if (get_max_size () < n)
3058 0 : throw_allocation_size_error ();
3059 0 : return unchecked_allocate (n);
3060 : }
3061 :
3062 : protected:
3063 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
3064 : size_ty
3065 : unchecked_calculate_new_capacity (const size_ty minimum_required_capacity) const noexcept
3066 : {
3067 : const size_ty current_capacity = get_capacity ();
3068 :
3069 : assert (current_capacity < minimum_required_capacity);
3070 :
3071 2516 : if (get_max_size () - current_capacity <= current_capacity)
3072 : return get_max_size ();
3073 :
3074 : // Note: This growth factor might be theoretically superior, but in testing it falls flat:
3075 : // size_ty new_capacity = current_capacity + (current_capacity / 2);
3076 :
3077 3657 : const size_ty new_capacity = 2 * current_capacity;
3078 : if (new_capacity < minimum_required_capacity)
3079 : return minimum_required_capacity;
3080 : return new_capacity;
3081 : }
3082 :
3083 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
3084 : size_ty
3085 2344 : checked_calculate_new_capacity (const size_ty minimum_required_capacity) const
3086 : {
3087 2344 : if (get_max_size () < minimum_required_capacity)
3088 0 : throw_allocation_size_error ();
3089 2344 : return unchecked_calculate_new_capacity (minimum_required_capacity);
3090 : }
3091 :
3092 : template <unsigned I>
3093 : PLUMED_GCH_CPP20_CONSTEXPR
3094 : small_vector_base&
3095 4208848 : copy_assign_default (const small_vector_base<Allocator, I>& other)
3096 : {
3097 4208848 : if (get_capacity () < other.get_size ())
3098 : {
3099 : // Reallocate.
3100 : size_ty new_capacity = unchecked_calculate_new_capacity (other.get_size ());
3101 0 : ptr new_data_ptr = unchecked_allocate (new_capacity, other.allocation_end_ptr ());
3102 :
3103 : PLUMED_GCH_TRY
3104 : {
3105 0 : uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr);
3106 : }
3107 : PLUMED_GCH_CATCH (...)
3108 : {
3109 : deallocate (new_data_ptr, new_capacity);
3110 : PLUMED_GCH_THROW;
3111 : }
3112 :
3113 : reset_data (new_data_ptr, new_capacity, other.get_size ());
3114 : }
3115 : else
3116 : {
3117 4208848 : if (get_size () < other.get_size ())
3118 : {
3119 : // No reallocation, partially in uninitialized space.
3120 20368 : std::copy_n (other.begin_ptr (), get_size (), begin_ptr ());
3121 40736 : uninitialized_copy (
3122 : unchecked_next (other.begin_ptr (), get_size ()),
3123 : other.end_ptr (),
3124 : end_ptr ());
3125 : }
3126 : else
3127 : {
3128 4188480 : destroy_range (copy_range (other.begin_ptr (), other.end_ptr (), begin_ptr ()),
3129 : end_ptr ());
3130 : }
3131 :
3132 : // data_ptr and capacity do not change in this case.
3133 : set_size (other.get_size ());
3134 : }
3135 :
3136 : alloc_interface::operator= (other);
3137 4208848 : return *this;
3138 : }
3139 :
3140 : template <unsigned I, typename AT = alloc_traits,
3141 : typename std::enable_if<AT::propagate_on_container_copy_assignment::value
3142 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
3143 : &&! AT::is_always_equal::value
3144 : #endif
3145 : >::type * = nullptr>
3146 : PLUMED_GCH_CPP20_CONSTEXPR
3147 : small_vector_base&
3148 : copy_assign (const small_vector_base<Allocator, I>& other)
3149 : {
3150 : if (other.allocator_ref () == allocator_ref ())
3151 : return copy_assign_default (other);
3152 :
3153 : if (InlineCapacity < other.get_size ())
3154 : {
3155 : alloc_interface new_alloc (other);
3156 :
3157 : const size_ty new_capacity = other.get_size ();
3158 : const ptr new_data_ptr = new_alloc.allocate_with_hint (
3159 : new_capacity,
3160 : other.allocation_end_ptr ());
3161 :
3162 : PLUMED_GCH_TRY
3163 : {
3164 : uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr);
3165 : }
3166 : PLUMED_GCH_CATCH (...)
3167 : {
3168 : new_alloc.deallocate (new_data_ptr, new_capacity);
3169 : PLUMED_GCH_THROW;
3170 : }
3171 :
3172 : reset_data (new_data_ptr, new_capacity, other.get_size ());
3173 : alloc_interface::operator= (new_alloc);
3174 : }
3175 : else
3176 : {
3177 : if (has_allocation ())
3178 : {
3179 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
3180 : ptr new_data_ptr;
3181 : if (std::is_constant_evaluated ())
3182 : {
3183 : alloc_interface new_alloc (other);
3184 : new_data_ptr = new_alloc.allocate (InlineCapacity);
3185 : }
3186 : else
3187 : new_data_ptr = storage_ptr ();
3188 : #else
3189 : const ptr new_data_ptr = storage_ptr ();
3190 : #endif
3191 :
3192 : uninitialized_copy (other.begin_ptr (), other.end_ptr (), new_data_ptr);
3193 : destroy_range (begin_ptr (), end_ptr ());
3194 : deallocate (data_ptr (), get_capacity ());
3195 : set_data_ptr (new_data_ptr);
3196 : set_capacity (InlineCapacity);
3197 : }
3198 : else if (get_size () < other.get_size ())
3199 : {
3200 : std::copy_n (other.begin_ptr (), get_size (), begin_ptr ());
3201 : uninitialized_copy (
3202 : unchecked_next (other.begin_ptr (), get_size ()),
3203 : other.end_ptr (),
3204 : end_ptr ());
3205 : }
3206 : else
3207 : {
3208 : destroy_range (copy_range (other.begin_ptr (), other.end_ptr (), begin_ptr ()),
3209 : end_ptr ());
3210 : }
3211 : set_size (other.get_size ());
3212 : alloc_interface::operator= (other);
3213 : }
3214 :
3215 : return *this;
3216 : }
3217 :
3218 : template <unsigned I, typename AT = alloc_traits,
3219 : typename std::enable_if<! AT::propagate_on_container_copy_assignment::value
3220 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
3221 : || AT::is_always_equal::value
3222 : #endif
3223 : >::type * = nullptr>
3224 : PLUMED_GCH_CPP20_CONSTEXPR
3225 : small_vector_base&
3226 : copy_assign (const small_vector_base<Allocator, I>& other)
3227 : {
3228 : return copy_assign_default (other);
3229 : }
3230 :
3231 : template <unsigned I>
3232 : PLUMED_GCH_CPP20_CONSTEXPR
3233 : void
3234 : move_allocation_pointer (small_vector_base<alloc_ty, I>&& other) noexcept
3235 : {
3236 : reset_data (other.data_ptr (), other.get_capacity (), other.get_size ());
3237 : other.set_default ();
3238 : }
3239 :
3240 : template <unsigned N = InlineCapacity, typename std::enable_if<N == 0>::type * = nullptr>
3241 : PLUMED_GCH_CPP20_CONSTEXPR
3242 : small_vector_base&
3243 : move_assign_default (small_vector_base&& other) noexcept
3244 : {
3245 : move_allocation_pointer (std::move (other));
3246 : alloc_interface::operator= (std::move (other));
3247 : return *this;
3248 : }
3249 :
3250 : template <unsigned LessEqualI,
3251 : typename std::enable_if<(LessEqualI <= InlineCapacity)>::type * = nullptr>
3252 : PLUMED_GCH_CPP20_CONSTEXPR
3253 : small_vector_base&
3254 : move_assign_default (small_vector_base<Allocator, LessEqualI>&& other)
3255 : noexcept (std::is_nothrow_move_assignable<value_ty>::value
3256 : && std::is_nothrow_move_constructible<value_ty>::value)
3257 : {
3258 : // We only move the allocation pointer over if it has strictly greater capacity than
3259 : // the inline capacity of `*this` because allocations can never have a smaller capacity
3260 : // than the inline capacity.
3261 : if (InlineCapacity < other.get_capacity ())
3262 : move_allocation_pointer (std::move (other));
3263 : else
3264 : {
3265 : // We are guaranteed to have sufficient capacity to store the elements.
3266 : if (InlineCapacity < get_capacity ())
3267 : {
3268 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
3269 : ptr new_data_ptr;
3270 : if (std::is_constant_evaluated ())
3271 : new_data_ptr = other.allocate (InlineCapacity);
3272 : else
3273 : new_data_ptr = storage_ptr ();
3274 : #else
3275 : const ptr new_data_ptr = storage_ptr ();
3276 : #endif
3277 :
3278 : uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr);
3279 : destroy_range (begin_ptr (), end_ptr ());
3280 : deallocate (data_ptr (), get_capacity ());
3281 : set_data_ptr (new_data_ptr);
3282 : set_capacity (InlineCapacity);
3283 : }
3284 : else if (get_size () < other.get_size ())
3285 : {
3286 : // There are more elements in `other`.
3287 : // Overwrite the existing range and uninitialized move the rest.
3288 : ptr other_pivot = unchecked_next (other.begin_ptr (), get_size ());
3289 : std::move (other.begin_ptr (), other_pivot, begin_ptr ());
3290 : uninitialized_move (other_pivot, other.end_ptr (), end_ptr ());
3291 : }
3292 : else
3293 : {
3294 : // There are the same number or fewer elements in `other`.
3295 : // Overwrite part of the existing range and destroy the rest.
3296 : ptr new_end = std::move (other.begin_ptr (), other.end_ptr (), begin_ptr ());
3297 : destroy_range (new_end, end_ptr ());
3298 : }
3299 :
3300 : set_size (other.get_size ());
3301 :
3302 : // Note: We do not need to deallocate any allocations in `other` because the value of
3303 : // an object meeting the Allocator named requirements does not change value after
3304 : // a move.
3305 : }
3306 :
3307 : alloc_interface::operator= (std::move (other));
3308 : return *this;
3309 : }
3310 :
3311 : template <unsigned GreaterI,
3312 : typename std::enable_if<(InlineCapacity < GreaterI)>::type * = nullptr>
3313 : PLUMED_GCH_CPP20_CONSTEXPR
3314 : small_vector_base&
3315 : move_assign_default (small_vector_base<Allocator, GreaterI>&& other)
3316 : {
3317 : if (other.has_allocation ())
3318 : move_allocation_pointer (std::move (other));
3319 : else if (get_capacity () < other.get_size ()
3320 : || (has_allocation () && ! (other.allocator_ref () == allocator_ref ())))
3321 : {
3322 : // Reallocate.
3323 :
3324 : // The compiler should be able to optimize this.
3325 : size_ty new_capacity =
3326 : get_capacity () < other.get_size ()
3327 : ? unchecked_calculate_new_capacity (other.get_size ())
3328 : : get_capacity ();
3329 :
3330 : ptr new_data_ptr = other.allocate_with_hint (new_capacity, other.allocation_end_ptr ());
3331 :
3332 : PLUMED_GCH_TRY
3333 : {
3334 : uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr);
3335 : }
3336 : PLUMED_GCH_CATCH (...)
3337 : {
3338 : other.deallocate (new_data_ptr, new_capacity);
3339 : PLUMED_GCH_THROW;
3340 : }
3341 :
3342 : reset_data (new_data_ptr, new_capacity, other.get_size ());
3343 : }
3344 : else
3345 : {
3346 : if (get_size () < other.get_size ())
3347 : {
3348 : // There are more elements in `other`.
3349 : // Overwrite the existing range and uninitialized move the rest.
3350 : ptr other_pivot = unchecked_next (other.begin_ptr (), get_size ());
3351 : std::move (other.begin_ptr (), other_pivot, begin_ptr ());
3352 : uninitialized_move (other_pivot, other.end_ptr (), end_ptr ());
3353 : }
3354 : else
3355 : {
3356 : // fewer elements in other
3357 : // overwrite part of the existing range and destroy the rest
3358 : ptr new_end = std::move (other.begin_ptr (), other.end_ptr (), begin_ptr ());
3359 : destroy_range (new_end, end_ptr ());
3360 : }
3361 :
3362 : // `data_ptr` and `capacity` do not change in this case.
3363 : set_size (other.get_size ());
3364 : }
3365 :
3366 : alloc_interface::operator= (std::move (other));
3367 : return *this;
3368 : }
3369 :
3370 : template <unsigned I>
3371 : PLUMED_GCH_CPP20_CONSTEXPR
3372 : small_vector_base&
3373 : move_assign_unequal_no_propagate (small_vector_base<Allocator, I>&& other)
3374 : {
3375 : if (get_capacity () < other.get_size ())
3376 : {
3377 : // Reallocate.
3378 : size_ty new_capacity = unchecked_calculate_new_capacity (other.get_size ());
3379 : ptr new_data_ptr = unchecked_allocate (new_capacity, other.allocation_end_ptr ());
3380 :
3381 : PLUMED_GCH_TRY
3382 : {
3383 : uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr);
3384 : }
3385 : PLUMED_GCH_CATCH (...)
3386 : {
3387 : deallocate (new_data_ptr, new_capacity);
3388 : PLUMED_GCH_THROW;
3389 : }
3390 :
3391 : reset_data (new_data_ptr, new_capacity, other.get_size ());
3392 : }
3393 : else
3394 : {
3395 : if (get_size () < other.get_size ())
3396 : {
3397 : // There are more elements in `other`.
3398 : // Overwrite the existing range and uninitialized move the rest.
3399 : ptr other_pivot = unchecked_next (other.begin_ptr (), get_size ());
3400 : std::move (other.begin_ptr (), other_pivot, begin_ptr ());
3401 : uninitialized_move (other_pivot, other.end_ptr (), end_ptr ());
3402 : }
3403 : else
3404 : {
3405 : // There are fewer elements in `other`.
3406 : // Overwrite part of the existing range and destroy the rest.
3407 : destroy_range (
3408 : std::move (other.begin_ptr (), other.end_ptr (), begin_ptr ()),
3409 : end_ptr ());
3410 : }
3411 :
3412 : // data_ptr and capacity do not change in this case
3413 : set_size (other.get_size ());
3414 : }
3415 :
3416 : alloc_interface::operator= (std::move (other));
3417 : return *this;
3418 : }
3419 :
3420 : template <unsigned I, typename A = alloc_ty,
3421 : typename std::enable_if<allocations_are_movable<A>::value>::type * = nullptr>
3422 : PLUMED_GCH_CPP20_CONSTEXPR
3423 : small_vector_base&
3424 : move_assign (small_vector_base<Allocator, I>&& other)
3425 : noexcept (noexcept (
3426 : std::declval<small_vector_base&> ().move_assign_default (std::move (other))))
3427 : {
3428 : return move_assign_default (std::move (other));
3429 : }
3430 :
3431 : template <unsigned I, typename A = alloc_ty,
3432 : typename std::enable_if<! allocations_are_movable<A>::value>::type * = nullptr>
3433 : PLUMED_GCH_CPP20_CONSTEXPR
3434 : small_vector_base&
3435 : move_assign (small_vector_base<Allocator, I>&& other)
3436 : {
3437 : if (other.allocator_ref () == allocator_ref ())
3438 : return move_assign_default (std::move (other));
3439 : return move_assign_unequal_no_propagate (std::move (other));
3440 : }
3441 :
3442 : template <unsigned I = InlineCapacity,
3443 : typename std::enable_if<I == 0>::type * = nullptr>
3444 : PLUMED_GCH_CPP20_CONSTEXPR
3445 : void
3446 : move_initialize (small_vector_base&& other) noexcept
3447 : {
3448 : set_data (other.data_ptr (), other.get_capacity (), other.get_size ());
3449 : other.set_default ();
3450 : }
3451 :
3452 : template <unsigned LessEqualI,
3453 : typename std::enable_if<(LessEqualI <= InlineCapacity)>::type * = nullptr>
3454 : PLUMED_GCH_CPP20_CONSTEXPR
3455 : void
3456 : move_initialize (small_vector_base<Allocator, LessEqualI>&& other)
3457 : noexcept (std::is_nothrow_move_constructible<value_ty>::value)
3458 : {
3459 : if (InlineCapacity < other.get_capacity ())
3460 : {
3461 : set_data (other.data_ptr (), other.get_capacity (), other.get_size ());
3462 : other.set_default ();
3463 : }
3464 : else
3465 : {
3466 : set_to_inline_storage ();
3467 : uninitialized_move (other.begin_ptr (), other.end_ptr (), data_ptr ());
3468 : set_size (other.get_size ());
3469 : }
3470 : }
3471 :
3472 : template <unsigned GreaterI,
3473 : typename std::enable_if<(InlineCapacity < GreaterI)>::type * = nullptr>
3474 : PLUMED_GCH_CPP20_CONSTEXPR
3475 : void
3476 : move_initialize (small_vector_base<Allocator, GreaterI>&& other)
3477 : {
3478 : if (other.has_allocation ())
3479 : {
3480 : set_data (other.data_ptr (), other.get_capacity (), other.get_size ());
3481 : other.set_default ();
3482 : }
3483 : else
3484 : {
3485 : if (InlineCapacity < other.get_size ())
3486 : {
3487 : // We may throw in this case.
3488 : set_data_ptr (unchecked_allocate (other.get_size (), other.allocation_end_ptr ()));
3489 : set_capacity (other.get_size ());
3490 :
3491 : PLUMED_GCH_TRY
3492 : {
3493 : uninitialized_move (other.begin_ptr (), other.end_ptr (), data_ptr ());
3494 : }
3495 : PLUMED_GCH_CATCH (...)
3496 : {
3497 : deallocate (data_ptr (), get_capacity ());
3498 : PLUMED_GCH_THROW;
3499 : }
3500 : }
3501 : else
3502 : {
3503 : set_to_inline_storage ();
3504 : uninitialized_move (other.begin_ptr (), other.end_ptr (), data_ptr ());
3505 : }
3506 :
3507 : set_size (other.get_size ());
3508 : }
3509 : }
3510 :
3511 : public:
3512 : // small_vector_base (void) = impl;
3513 : small_vector_base (const small_vector_base&) = delete;
3514 : small_vector_base (small_vector_base&&) noexcept = delete;
3515 : small_vector_base& operator= (const small_vector_base&) = delete;
3516 : small_vector_base& operator= (small_vector_base&&) noexcept = delete;
3517 : // ~small_vector_base (void) = impl;
3518 :
3519 : PLUMED_GCH_CPP20_CONSTEXPR
3520 1609758 : small_vector_base (void) noexcept
3521 : {
3522 : set_default ();
3523 : }
3524 :
3525 : static constexpr struct bypass_tag { } bypass { };
3526 :
3527 : template <unsigned I, typename ...MaybeAlloc>
3528 : PLUMED_GCH_CPP20_CONSTEXPR
3529 : small_vector_base (bypass_tag,
3530 : const small_vector_base<Allocator, I>& other,
3531 : const MaybeAlloc&... alloc)
3532 : : alloc_interface (other, alloc...)
3533 : {
3534 : if (InlineCapacity < other.get_size ())
3535 : {
3536 : set_data_ptr (unchecked_allocate (other.get_size (), other.allocation_end_ptr ()));
3537 : set_capacity (other.get_size ());
3538 :
3539 : PLUMED_GCH_TRY
3540 : {
3541 : uninitialized_copy (other.begin_ptr (), other.end_ptr (), data_ptr ());
3542 : }
3543 : PLUMED_GCH_CATCH (...)
3544 : {
3545 : deallocate (data_ptr (), get_capacity ());
3546 : PLUMED_GCH_THROW;
3547 : }
3548 : }
3549 : else
3550 : {
3551 : set_to_inline_storage ();
3552 : uninitialized_copy (other.begin_ptr (), other.end_ptr (), data_ptr ());
3553 : }
3554 :
3555 : set_size (other.get_size ());
3556 : }
3557 :
3558 : template <unsigned I>
3559 : PLUMED_GCH_CPP20_CONSTEXPR
3560 : small_vector_base (bypass_tag, small_vector_base<Allocator, I>&& other)
3561 : noexcept (std::is_nothrow_move_constructible<value_ty>::value
3562 : || (I == 0 && I == InlineCapacity))
3563 : : alloc_interface (std::move (other))
3564 : {
3565 : move_initialize (std::move (other));
3566 : }
3567 :
3568 : template <unsigned I, typename A = alloc_ty,
3569 : typename std::enable_if<std::is_same<std::allocator<value_ty>, A>::value
3570 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
3571 : || std::allocator_traits<A>::is_always_equal::value
3572 : #endif
3573 : >::type * = nullptr>
3574 : PLUMED_GCH_CPP20_CONSTEXPR
3575 : small_vector_base (bypass_tag, small_vector_base<Allocator, I>&& other, const alloc_ty&)
3576 : noexcept (noexcept (small_vector_base (bypass, std::move (other))))
3577 : : small_vector_base (bypass, std::move (other))
3578 : { }
3579 :
3580 : template <unsigned I, typename A = alloc_ty,
3581 : typename std::enable_if<! (std::is_same<std::allocator<value_ty>, A>::value
3582 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
3583 : || std::allocator_traits<A>::is_always_equal::value
3584 : #endif
3585 : )>::type * = nullptr>
3586 : PLUMED_GCH_CPP20_CONSTEXPR
3587 : small_vector_base (bypass_tag, small_vector_base<Allocator, I>&& other, const alloc_ty& alloc)
3588 : : alloc_interface (alloc)
3589 : {
3590 : if (other.allocator_ref () == alloc)
3591 : {
3592 : move_initialize (std::move (other));
3593 : return;
3594 : }
3595 :
3596 : if (InlineCapacity < other.get_size ())
3597 : {
3598 : // We may throw in this case.
3599 : set_data_ptr (unchecked_allocate (other.get_size (), other.allocation_end_ptr ()));
3600 : set_capacity (other.get_size ());
3601 :
3602 : PLUMED_GCH_TRY
3603 : {
3604 : uninitialized_move (other.begin_ptr (), other.end_ptr (), data_ptr ());
3605 : }
3606 : PLUMED_GCH_CATCH (...)
3607 : {
3608 : deallocate (data_ptr (), get_capacity ());
3609 : PLUMED_GCH_THROW;
3610 : }
3611 : }
3612 : else
3613 : {
3614 : set_to_inline_storage ();
3615 : uninitialized_move (other.begin_ptr (), other.end_ptr (), data_ptr ());
3616 : }
3617 :
3618 : set_size (other.get_size ());
3619 : }
3620 :
3621 : PLUMED_GCH_CPP20_CONSTEXPR explicit
3622 : small_vector_base (const alloc_ty& alloc) noexcept
3623 : : alloc_interface (alloc)
3624 : {
3625 : set_default ();
3626 : }
3627 :
3628 : PLUMED_GCH_CPP20_CONSTEXPR
3629 3738 : small_vector_base (size_ty count, const alloc_ty& alloc)
3630 : : alloc_interface (alloc)
3631 : {
3632 3738 : if (InlineCapacity < count)
3633 : {
3634 0 : set_data_ptr (checked_allocate (count));
3635 : set_capacity (count);
3636 : }
3637 : else
3638 : set_to_inline_storage ();
3639 :
3640 : PLUMED_GCH_TRY
3641 : {
3642 3738 : uninitialized_value_construct (begin_ptr (), unchecked_next (begin_ptr (), count));
3643 : }
3644 : PLUMED_GCH_CATCH (...)
3645 : {
3646 : if (has_allocation ())
3647 : deallocate (data_ptr (), get_capacity ());
3648 : PLUMED_GCH_THROW;
3649 : }
3650 : set_size (count);
3651 3738 : }
3652 :
3653 : PLUMED_GCH_CPP20_CONSTEXPR
3654 : small_vector_base (size_ty count, const value_ty& val, const alloc_ty& alloc)
3655 : : alloc_interface (alloc)
3656 : {
3657 : if (InlineCapacity < count)
3658 : {
3659 : set_data_ptr (checked_allocate (count));
3660 : set_capacity (count);
3661 : }
3662 : else
3663 : set_to_inline_storage ();
3664 :
3665 : PLUMED_GCH_TRY
3666 : {
3667 : uninitialized_fill (begin_ptr (), unchecked_next (begin_ptr (), count), val);
3668 : }
3669 : PLUMED_GCH_CATCH (...)
3670 : {
3671 : if (has_allocation ())
3672 : deallocate (data_ptr (), get_capacity ());
3673 : PLUMED_GCH_THROW;
3674 : }
3675 : set_size (count);
3676 : }
3677 :
3678 : template <typename Generator>
3679 : PLUMED_GCH_CPP20_CONSTEXPR
3680 : small_vector_base (size_ty count, Generator& g, const alloc_ty& alloc)
3681 : : alloc_interface (alloc)
3682 : {
3683 : if (InlineCapacity < count)
3684 : {
3685 : set_data_ptr (checked_allocate (count));
3686 : set_capacity (count);
3687 : }
3688 : else
3689 : set_to_inline_storage ();
3690 :
3691 : ptr curr = begin_ptr ();
3692 : const ptr new_end = unchecked_next (begin_ptr (), count);
3693 : PLUMED_GCH_TRY
3694 : {
3695 : for (; ! (curr == new_end); ++curr)
3696 : construct (curr, g ());
3697 : }
3698 : PLUMED_GCH_CATCH (...)
3699 : {
3700 : destroy_range (begin_ptr (), curr);
3701 : if (has_allocation ())
3702 : deallocate (data_ptr (), get_capacity ());
3703 : PLUMED_GCH_THROW;
3704 : }
3705 : set_size (count);
3706 : }
3707 :
3708 : #ifdef PLUMED_GCH_LIB_CONCEPTS
3709 : template <std::input_iterator InputIt>
3710 : #else
3711 : template <typename InputIt>
3712 : #endif
3713 : PLUMED_GCH_CPP20_CONSTEXPR
3714 : small_vector_base (InputIt first, InputIt last, std::input_iterator_tag,
3715 : const alloc_ty& alloc)
3716 : : small_vector_base (alloc)
3717 : {
3718 : using iterator_cat = typename std::iterator_traits<InputIt>::iterator_category;
3719 : append_range (first, last, iterator_cat { });
3720 : }
3721 :
3722 : #ifdef PLUMED_GCH_LIB_CONCEPTS
3723 : template <std::forward_iterator ForwardIt>
3724 : #else
3725 : template <typename ForwardIt>
3726 : #endif
3727 : PLUMED_GCH_CPP20_CONSTEXPR
3728 : small_vector_base (ForwardIt first, ForwardIt last, std::forward_iterator_tag,
3729 : const alloc_ty& alloc)
3730 : : alloc_interface (alloc)
3731 : {
3732 : size_ty count = external_range_length (first, last);
3733 : if (InlineCapacity < count)
3734 : {
3735 : set_data_ptr (unchecked_allocate (count));
3736 : set_capacity (count);
3737 : PLUMED_GCH_TRY
3738 : {
3739 : uninitialized_copy (first, last, begin_ptr ());
3740 : }
3741 : PLUMED_GCH_CATCH (...)
3742 : {
3743 : deallocate (data_ptr (), get_capacity ());
3744 : PLUMED_GCH_THROW;
3745 : }
3746 : }
3747 : else
3748 : {
3749 : set_to_inline_storage ();
3750 : uninitialized_copy (first, last, begin_ptr ());
3751 : }
3752 :
3753 : set_size (count);
3754 : }
3755 :
3756 : PLUMED_GCH_CPP20_CONSTEXPR
3757 : ~small_vector_base (void) noexcept
3758 : {
3759 : assert (InlineCapacity <= get_capacity () && "Invalid capacity.");
3760 1428222 : wipe ();
3761 : }
3762 :
3763 : protected:
3764 :
3765 : PLUMED_GCH_CPP20_CONSTEXPR
3766 : void
3767 : set_to_inline_storage (void)
3768 : {
3769 : set_capacity (InlineCapacity);
3770 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
3771 : if (std::is_constant_evaluated ())
3772 : return set_data_ptr (alloc_interface::allocate (InlineCapacity));
3773 : #endif
3774 : set_data_ptr (storage_ptr ());
3775 3738 : }
3776 :
3777 : PLUMED_GCH_CPP20_CONSTEXPR
3778 : void
3779 : assign_with_copies (size_ty count, const value_ty& val)
3780 : {
3781 : if (get_capacity () < count)
3782 : {
3783 : size_ty new_capacity = checked_calculate_new_capacity (count);
3784 : ptr new_begin = unchecked_allocate (new_capacity);
3785 :
3786 : PLUMED_GCH_TRY
3787 : {
3788 : uninitialized_fill (new_begin, unchecked_next (new_begin, count), val);
3789 : }
3790 : PLUMED_GCH_CATCH (...)
3791 : {
3792 : deallocate (new_begin, new_capacity);
3793 : PLUMED_GCH_THROW;
3794 : }
3795 :
3796 : reset_data (new_begin, new_capacity, count);
3797 : }
3798 : else if (get_size () < count)
3799 : {
3800 : std::fill (begin_ptr (), end_ptr (), val);
3801 : uninitialized_fill (end_ptr (), unchecked_next (begin_ptr (), count), val);
3802 : set_size (count);
3803 : }
3804 : else
3805 : erase_range (std::fill_n (begin_ptr (), count, val), end_ptr ());
3806 : }
3807 :
3808 : template <typename InputIt,
3809 : typename std::enable_if<std::is_assignable<
3810 : value_ty&,
3811 : decltype (*std::declval<InputIt> ())>::value>::type * = nullptr>
3812 : PLUMED_GCH_CPP20_CONSTEXPR
3813 : void
3814 : assign_with_range (InputIt first, InputIt last, std::input_iterator_tag)
3815 : {
3816 : using iterator_cat = typename std::iterator_traits<InputIt>::iterator_category;
3817 :
3818 : ptr curr = begin_ptr ();
3819 : for (; ! (end_ptr () == curr || first == last); ++curr, static_cast<void> (++first))
3820 : *curr = *first;
3821 :
3822 : if (first == last)
3823 : erase_to_end (curr);
3824 : else
3825 : append_range (first, last, iterator_cat { });
3826 : }
3827 :
3828 : template <typename ForwardIt,
3829 : typename std::enable_if<std::is_assignable<
3830 : value_ty&,
3831 : decltype (*std::declval<ForwardIt> ())>::value>::type * = nullptr>
3832 : PLUMED_GCH_CPP20_CONSTEXPR
3833 : void
3834 : assign_with_range (ForwardIt first, ForwardIt last, std::forward_iterator_tag)
3835 : {
3836 : const size_ty count = external_range_length (first, last);
3837 : if (get_capacity () < count)
3838 : {
3839 : size_ty new_capacity = checked_calculate_new_capacity (count);
3840 : ptr new_begin = unchecked_allocate (new_capacity);
3841 :
3842 : PLUMED_GCH_TRY
3843 : {
3844 : uninitialized_copy (first, last, new_begin);
3845 : }
3846 : PLUMED_GCH_CATCH (...)
3847 : {
3848 : deallocate (new_begin, new_capacity);
3849 : PLUMED_GCH_THROW;
3850 : }
3851 :
3852 : reset_data (new_begin, new_capacity, count);
3853 : }
3854 : else if (get_size () < count)
3855 : {
3856 : ForwardIt pivot = copy_n_return_in (first, get_size (), begin_ptr ());
3857 : uninitialized_copy (pivot, last, end_ptr ());
3858 : set_size (count);
3859 : }
3860 : else
3861 : erase_range (copy_range (first, last, begin_ptr ()), end_ptr ());
3862 : }
3863 :
3864 : template <typename InputIt,
3865 : typename std::enable_if<! std::is_assignable<
3866 : value_ty&,
3867 : decltype (*std::declval<InputIt> ())>::value>::type * = nullptr>
3868 : PLUMED_GCH_CPP20_CONSTEXPR
3869 : void
3870 : assign_with_range (InputIt first, InputIt last, std::input_iterator_tag)
3871 : {
3872 : using iterator_cat = typename std::iterator_traits<InputIt>::iterator_category;
3873 :
3874 : // If not assignable then destroy all elements and append.
3875 : erase_all ();
3876 : append_range (first, last, iterator_cat { });
3877 : }
3878 :
3879 : // Ie. move-if-noexcept.
3880 : struct strong_exception_policy
3881 : { };
3882 :
3883 : template <typename Policy = void, typename V = value_ty,
3884 : typename std::enable_if<is_explicitly_move_insertable<V>::value
3885 : && (! std::is_same<Policy, strong_exception_policy>::value
3886 : || relocate_with_move<V>::value),
3887 : bool>::type = true>
3888 : PLUMED_GCH_CPP20_CONSTEXPR
3889 : ptr
3890 : uninitialized_move (ptr first, ptr last, ptr d_first)
3891 : noexcept (std::is_nothrow_move_constructible<value_ty>::value)
3892 : {
3893 : return uninitialized_copy (std::make_move_iterator (first),
3894 : std::make_move_iterator (last),
3895 : d_first);
3896 : }
3897 :
3898 : template <typename Policy = void, typename V = value_ty,
3899 : typename std::enable_if<! is_explicitly_move_insertable<V>::value
3900 : || ( std::is_same<Policy, strong_exception_policy>::value
3901 : &&! relocate_with_move<V>::value),
3902 : bool>::type = false>
3903 : PLUMED_GCH_CPP20_CONSTEXPR
3904 : ptr
3905 : uninitialized_move (ptr first, ptr last, ptr d_first)
3906 : noexcept (alloc_interface::template is_uninitialized_memcpyable_iterator<ptr>::value)
3907 : {
3908 : return uninitialized_copy (first, last, d_first);
3909 : }
3910 :
3911 : PLUMED_GCH_CPP20_CONSTEXPR
3912 : ptr
3913 : shift_into_uninitialized (ptr pos, size_ty n_shift)
3914 : {
3915 : // Shift elements over to the right into uninitialized space.
3916 : // Returns the start of the shifted range.
3917 : // Precondition: shift < end_ptr () - pos
3918 : assert (n_shift != 0 && "The value of `n_shift` should not be 0.");
3919 :
3920 : const ptr original_end = end_ptr ();
3921 : const ptr pivot = unchecked_prev (original_end, n_shift);
3922 :
3923 : uninitialized_move (pivot, original_end, original_end);
3924 : increase_size (n_shift);
3925 : return move_right (pos, pivot, original_end);
3926 : }
3927 :
3928 : template <typename ...Args>
3929 : PLUMED_GCH_CPP20_CONSTEXPR
3930 : ptr
3931 2150913 : append_element (Args&&... args)
3932 : {
3933 2150913 : if (get_size () < get_capacity ())
3934 2149600 : return emplace_into_current_end (std::forward<Args> (args)...);
3935 1313 : return emplace_into_reallocation_end (std::forward<Args> (args)...);
3936 : }
3937 :
3938 : PLUMED_GCH_CPP20_CONSTEXPR
3939 : ptr
3940 : append_copies (size_ty count, const value_ty& val)
3941 : {
3942 : if (num_uninitialized () < count)
3943 : {
3944 : // Reallocate.
3945 : if (get_max_size () - get_size () < count)
3946 : throw_allocation_size_error ();
3947 :
3948 : size_ty original_size = get_size ();
3949 : size_ty new_size = get_size () + count;
3950 :
3951 : // The check is handled by the if-guard.
3952 : size_ty new_capacity = unchecked_calculate_new_capacity (new_size);
3953 : ptr new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
3954 : ptr new_last = unchecked_next (new_data_ptr, original_size);
3955 :
3956 : PLUMED_GCH_TRY
3957 : {
3958 : new_last = uninitialized_fill (new_last, unchecked_next (new_last, count), val);
3959 : uninitialized_move (begin_ptr (), end_ptr (), new_data_ptr);
3960 : }
3961 : PLUMED_GCH_CATCH (...)
3962 : {
3963 : destroy_range (unchecked_next (new_data_ptr, original_size), new_last);
3964 : deallocate (new_data_ptr, new_capacity);
3965 : PLUMED_GCH_THROW;
3966 : }
3967 :
3968 : reset_data (new_data_ptr, new_capacity, new_size);
3969 : return unchecked_next (new_data_ptr, original_size);
3970 : }
3971 : else
3972 : {
3973 : const ptr ret = end_ptr ();
3974 : uninitialized_fill (ret, unchecked_next (ret, count), val);
3975 : increase_size (count);
3976 : return ret;
3977 : }
3978 : }
3979 :
3980 : template <typename MovePolicy, typename InputIt,
3981 : typename std::enable_if<
3982 : std::is_same<MovePolicy, strong_exception_policy>::value, bool>::type = true>
3983 : PLUMED_GCH_CPP20_CONSTEXPR
3984 : ptr
3985 : append_range (InputIt first, InputIt last, std::input_iterator_tag)
3986 : {
3987 : // Append with a strong exception guarantee.
3988 : size_ty original_size = get_size ();
3989 : for (; ! (first == last); ++first)
3990 : {
3991 : PLUMED_GCH_TRY
3992 : {
3993 : append_element (*first);
3994 : }
3995 : PLUMED_GCH_CATCH (...)
3996 : {
3997 : erase_range (unchecked_next (begin_ptr (), original_size), end_ptr ());
3998 : PLUMED_GCH_THROW;
3999 : }
4000 : }
4001 : return unchecked_next (begin_ptr (), original_size);
4002 : }
4003 :
4004 : template <typename MovePolicy = void, typename InputIt,
4005 : typename std::enable_if<
4006 : ! std::is_same<MovePolicy, strong_exception_policy>::value, bool>::type = false>
4007 : PLUMED_GCH_CPP20_CONSTEXPR
4008 : ptr
4009 : append_range (InputIt first, InputIt last, std::input_iterator_tag)
4010 : {
4011 : size_ty original_size = get_size ();
4012 : for (; ! (first == last); ++first)
4013 : append_element (*first);
4014 : return unchecked_next (begin_ptr (), original_size);
4015 : }
4016 :
4017 : template <typename MovePolicy = void, typename ForwardIt>
4018 : PLUMED_GCH_CPP20_CONSTEXPR
4019 : ptr
4020 : append_range (ForwardIt first, ForwardIt last, std::forward_iterator_tag)
4021 : {
4022 : const size_ty num_insert = external_range_length (first, last);
4023 :
4024 : if (num_uninitialized () < num_insert)
4025 : {
4026 : // Reallocate.
4027 : if (get_max_size () - get_size () < num_insert)
4028 : throw_allocation_size_error ();
4029 :
4030 : size_ty original_size = get_size ();
4031 : size_ty new_size = get_size () + num_insert;
4032 :
4033 : // The check is handled by the if-guard.
4034 : size_ty new_capacity = unchecked_calculate_new_capacity (new_size);
4035 : ptr new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
4036 : ptr new_last = unchecked_next (new_data_ptr, original_size);
4037 :
4038 : PLUMED_GCH_TRY
4039 : {
4040 : new_last = uninitialized_copy (first, last, new_last);
4041 : uninitialized_move<MovePolicy> (begin_ptr (), end_ptr (), new_data_ptr);
4042 : }
4043 : PLUMED_GCH_CATCH (...)
4044 : {
4045 : destroy_range (unchecked_next (new_data_ptr, original_size), new_last);
4046 : deallocate (new_data_ptr, new_capacity);
4047 : PLUMED_GCH_THROW;
4048 : }
4049 :
4050 : reset_data (new_data_ptr, new_capacity, new_size);
4051 : return unchecked_next (new_data_ptr, original_size);
4052 : }
4053 : else
4054 : {
4055 : ptr ret = end_ptr ();
4056 : uninitialized_copy (first, last, ret);
4057 : increase_size (num_insert);
4058 : return ret;
4059 : }
4060 : }
4061 :
4062 : template <typename ...Args>
4063 : PLUMED_GCH_CPP20_CONSTEXPR
4064 : ptr
4065 : emplace_at (ptr pos, Args&&... args)
4066 : {
4067 : assert (get_size () <= get_capacity () && "size was greater than capacity");
4068 :
4069 : if (get_size () < get_capacity ())
4070 : return emplace_into_current (pos, std::forward<Args> (args)...);
4071 : return emplace_into_reallocation (pos, std::forward<Args> (args)...);
4072 : }
4073 :
4074 : PLUMED_GCH_CPP20_CONSTEXPR
4075 : ptr
4076 : insert_copies (ptr pos, size_ty count, const value_ty& val)
4077 : {
4078 : if (0 == count)
4079 : return pos;
4080 :
4081 : if (end_ptr () == pos)
4082 : {
4083 : if (1 == count)
4084 : return append_element (val);
4085 : return append_copies (count, val);
4086 : }
4087 :
4088 : if (num_uninitialized () < count)
4089 : {
4090 : // Reallocate.
4091 : if (get_max_size () - get_size () < count)
4092 : throw_allocation_size_error ();
4093 :
4094 : const size_ty offset = internal_range_length (begin_ptr (), pos);
4095 :
4096 : const size_ty new_size = get_size () + count;
4097 :
4098 : // The check is handled by the if-guard.
4099 : const size_ty new_capacity = unchecked_calculate_new_capacity (new_size);
4100 : ptr new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
4101 : ptr new_first = unchecked_next (new_data_ptr, offset);
4102 : ptr new_last = new_first;
4103 :
4104 : PLUMED_GCH_TRY
4105 : {
4106 : uninitialized_fill (new_first, unchecked_next (new_first, count), val);
4107 : unchecked_advance (new_last, count);
4108 :
4109 : uninitialized_move (begin_ptr (), pos, new_data_ptr);
4110 : new_first = new_data_ptr;
4111 : uninitialized_move (pos, end_ptr (), new_last);
4112 : }
4113 : PLUMED_GCH_CATCH (...)
4114 : {
4115 : destroy_range (new_first, new_last);
4116 : deallocate (new_data_ptr, new_capacity);
4117 : PLUMED_GCH_THROW;
4118 : }
4119 :
4120 : reset_data (new_data_ptr, new_capacity, new_size);
4121 : return unchecked_next (begin_ptr (), offset);
4122 : }
4123 : else
4124 : {
4125 : // If we have fewer to insert than tailing elements after `pos`, we shift into
4126 : // uninitialized and then copy over.
4127 :
4128 : const size_ty tail_size = internal_range_length (pos, end_ptr ());
4129 : if (tail_size < count)
4130 : {
4131 : // The number inserted is larger than the number after `pos`,
4132 : // so part of the input will be used to construct new elements,
4133 : // and another part of it will assign existing ones.
4134 : // In order:
4135 : // Construct new elements immediately after end_ptr () using the input.
4136 : // Move-construct existing elements over to the tail.
4137 : // Assign existing elements using the input.
4138 :
4139 : ptr original_end = end_ptr ();
4140 :
4141 : // Place a portion of the input into the uninitialized section.
4142 : size_ty num_val_tail = count - tail_size;
4143 :
4144 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
4145 : if (std::is_constant_evaluated ())
4146 : {
4147 : uninitialized_fill (end_ptr (), unchecked_next (end_ptr (), num_val_tail), val);
4148 : increase_size (num_val_tail);
4149 :
4150 : const heap_temporary tmp (*this, val);
4151 :
4152 : uninitialized_move (pos, original_end, end_ptr ());
4153 : increase_size (tail_size);
4154 :
4155 : std::fill_n (pos, tail_size, tmp.get ());
4156 :
4157 : return pos;
4158 : }
4159 : #endif
4160 :
4161 : uninitialized_fill (end_ptr (), unchecked_next (end_ptr (), num_val_tail), val);
4162 : increase_size (num_val_tail);
4163 :
4164 : PLUMED_GCH_TRY
4165 : {
4166 : // We need to handle possible aliasing here.
4167 : const stack_temporary tmp (*this, val);
4168 :
4169 : // Now, move the tail to the end.
4170 : uninitialized_move (pos, original_end, end_ptr ());
4171 : increase_size (tail_size);
4172 :
4173 : PLUMED_GCH_TRY
4174 : {
4175 : // Finally, try to copy the rest of the elements over.
4176 : std::fill_n (pos, tail_size, tmp.get ());
4177 : }
4178 : PLUMED_GCH_CATCH (...)
4179 : {
4180 : // Attempt to roll back and destroy the tail if we fail.
4181 : ptr inserted_end = unchecked_prev (end_ptr (), tail_size);
4182 : move_left (inserted_end, end_ptr (), pos);
4183 : destroy_range (inserted_end, end_ptr ());
4184 : decrease_size (tail_size);
4185 : PLUMED_GCH_THROW;
4186 : }
4187 : }
4188 : PLUMED_GCH_CATCH (...)
4189 : {
4190 : // Destroy the elements constructed from the input.
4191 : destroy_range (original_end, end_ptr ());
4192 : decrease_size (internal_range_length (original_end, end_ptr ()));
4193 : PLUMED_GCH_THROW;
4194 : }
4195 : }
4196 : else
4197 : {
4198 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
4199 : if (std::is_constant_evaluated ())
4200 : {
4201 : const heap_temporary tmp (*this, val);
4202 :
4203 : ptr inserted_end = shift_into_uninitialized (pos, count);
4204 : std::fill (pos, inserted_end, tmp.get ());
4205 :
4206 : return pos;
4207 : }
4208 : #endif
4209 : const stack_temporary tmp (*this, val);
4210 :
4211 : ptr inserted_end = shift_into_uninitialized (pos, count);
4212 :
4213 : // Attempt to copy over the elements.
4214 : // If we fail we'll attempt a full roll-back.
4215 : PLUMED_GCH_TRY
4216 : {
4217 : std::fill (pos, inserted_end, tmp.get ());
4218 : }
4219 : PLUMED_GCH_CATCH (...)
4220 : {
4221 : ptr original_end = move_left (inserted_end, end_ptr (), pos);
4222 : destroy_range (original_end, end_ptr ());
4223 : decrease_size (count);
4224 : PLUMED_GCH_THROW;
4225 : }
4226 : }
4227 : return pos;
4228 : }
4229 : }
4230 :
4231 : template <typename ForwardIt>
4232 : PLUMED_GCH_CPP20_CONSTEXPR
4233 : ptr
4234 : insert_range_helper (ptr pos, ForwardIt first, ForwardIt last)
4235 : {
4236 : assert (! (first == last) && "The range should not be empty.");
4237 : assert (! (end_ptr () == pos) && "`pos` should not be at the end.");
4238 :
4239 : const size_ty num_insert = external_range_length (first, last);
4240 : if (num_uninitialized () < num_insert)
4241 : {
4242 : // Reallocate.
4243 : if (get_max_size () - get_size () < num_insert)
4244 : throw_allocation_size_error ();
4245 :
4246 : const size_ty offset = internal_range_length (begin_ptr (), pos);
4247 : const size_ty new_size = get_size () + num_insert;
4248 :
4249 : // The check is handled by the if-guard.
4250 : const size_ty new_capacity = unchecked_calculate_new_capacity (new_size);
4251 : const ptr new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
4252 : ptr new_first = unchecked_next (new_data_ptr, offset);
4253 : ptr new_last = new_first;
4254 :
4255 : PLUMED_GCH_TRY
4256 : {
4257 : uninitialized_copy (first, last, new_first);
4258 : unchecked_advance (new_last, num_insert);
4259 :
4260 : uninitialized_move (begin_ptr (), pos, new_data_ptr);
4261 : new_first = new_data_ptr;
4262 : uninitialized_move (pos, end_ptr (), new_last);
4263 : }
4264 : PLUMED_GCH_CATCH (...)
4265 : {
4266 : destroy_range (new_first, new_last);
4267 : deallocate (new_data_ptr, new_capacity);
4268 : PLUMED_GCH_THROW;
4269 : }
4270 :
4271 : reset_data (new_data_ptr, new_capacity, new_size);
4272 : return unchecked_next (begin_ptr (), offset);
4273 : }
4274 : else
4275 : {
4276 : // if we have fewer to insert than tailing elements after
4277 : // `pos` we shift into uninitialized and then copy over
4278 : const size_ty tail_size = internal_range_length (pos, end_ptr ());
4279 : if (tail_size < num_insert)
4280 : {
4281 : // Use the same method as insert_copies.
4282 : ptr original_end = end_ptr ();
4283 : ForwardIt pivot = unchecked_next (first, tail_size);
4284 :
4285 : // Place a portion of the input into the uninitialized section.
4286 : uninitialized_copy (pivot, last, end_ptr ());
4287 : increase_size (num_insert - tail_size);
4288 :
4289 : PLUMED_GCH_TRY
4290 : {
4291 : // Now move the tail to the end.
4292 : uninitialized_move (pos, original_end, end_ptr ());
4293 : increase_size (tail_size);
4294 :
4295 : PLUMED_GCH_TRY
4296 : {
4297 : // Finally, try to copy the rest of the elements over.
4298 : copy_range (first, pivot, pos);
4299 : }
4300 : PLUMED_GCH_CATCH (...)
4301 : {
4302 : // Attempt to roll back and destroy the tail if we fail.
4303 : ptr inserted_end = unchecked_prev (end_ptr (), tail_size);
4304 : move_left (inserted_end, end_ptr (), pos);
4305 : destroy_range (inserted_end, end_ptr ());
4306 : decrease_size (tail_size);
4307 : PLUMED_GCH_THROW;
4308 : }
4309 : }
4310 : PLUMED_GCH_CATCH (...)
4311 : {
4312 : // If we throw, destroy the first copy we made.
4313 : destroy_range (original_end, end_ptr ());
4314 : decrease_size (internal_range_length (original_end, end_ptr ()));
4315 : PLUMED_GCH_THROW;
4316 : }
4317 : }
4318 : else
4319 : {
4320 : shift_into_uninitialized (pos, num_insert);
4321 :
4322 : // Attempt to copy over the elements.
4323 : // If we fail we'll attempt a full roll-back.
4324 : PLUMED_GCH_TRY
4325 : {
4326 : copy_range (first, last, pos);
4327 : }
4328 : PLUMED_GCH_CATCH (...)
4329 : {
4330 : ptr inserted_end = unchecked_next (pos, num_insert);
4331 : ptr original_end = move_left (inserted_end, end_ptr (), pos);
4332 : destroy_range (original_end, end_ptr ());
4333 : decrease_size (num_insert);
4334 : PLUMED_GCH_THROW;
4335 : }
4336 : }
4337 : return pos;
4338 : }
4339 : }
4340 :
4341 : template <typename InputIt>
4342 : PLUMED_GCH_CPP20_CONSTEXPR
4343 : ptr
4344 : insert_range (ptr pos, InputIt first, InputIt last, std::input_iterator_tag)
4345 : {
4346 : assert (! (first == last) && "The range should not be empty.");
4347 :
4348 : // Ensure we use this specific overload to give a strong exception guarantee for 1 element.
4349 : if (end_ptr () == pos)
4350 : return append_range (first, last, std::input_iterator_tag { });
4351 :
4352 : using iterator_cat = typename std::iterator_traits<InputIt>::iterator_category;
4353 : small_vector_base tmp (first, last, iterator_cat { }, allocator_ref ());
4354 :
4355 : return insert_range_helper (
4356 : pos,
4357 : std::make_move_iterator (tmp.begin_ptr ()),
4358 : std::make_move_iterator (tmp.end_ptr ()));
4359 : }
4360 :
4361 : template <typename ForwardIt>
4362 : PLUMED_GCH_CPP20_CONSTEXPR
4363 : ptr
4364 : insert_range (ptr pos, ForwardIt first, ForwardIt last, std::forward_iterator_tag)
4365 : {
4366 : if (! (end_ptr () == pos))
4367 : return insert_range_helper (pos, first, last);
4368 :
4369 : if (unchecked_next (first) == last)
4370 : return append_element (*first);
4371 :
4372 : using iterator_cat = typename std::iterator_traits<ForwardIt>::iterator_category;
4373 : return append_range (first, last, iterator_cat { });
4374 : }
4375 :
4376 : template <typename ...Args>
4377 : PLUMED_GCH_CPP20_CONSTEXPR
4378 : ptr
4379 2149600 : emplace_into_current_end (Args&&... args)
4380 : {
4381 2149600 : construct (end_ptr (), std::forward<Args> (args)...);
4382 : increase_size (1);
4383 2149600 : return unchecked_prev (end_ptr ());
4384 : }
4385 :
4386 : template <typename V = value_ty,
4387 : typename std::enable_if<
4388 : std::is_nothrow_move_constructible<V>::value>::type * = nullptr>
4389 : PLUMED_GCH_CPP20_CONSTEXPR
4390 : ptr
4391 : emplace_into_current (ptr pos, value_ty&& val)
4392 : {
4393 : if (pos == end_ptr ())
4394 : return emplace_into_current_end (std::move (val));
4395 :
4396 : // In the special case of value_ty&& we don't make a copy because behavior is unspecified
4397 : // when it is an internal element. Hence, we'll take the opportunity to optimize and assume
4398 : // that it isn't an internal element.
4399 : shift_into_uninitialized (pos, 1);
4400 : destroy (pos);
4401 : construct (pos, std::move (val));
4402 : return pos;
4403 : }
4404 :
4405 : template <typename ...Args>
4406 : PLUMED_GCH_CPP20_CONSTEXPR
4407 : ptr
4408 : emplace_into_current (ptr pos, Args&&... args)
4409 : {
4410 : if (pos == end_ptr ())
4411 : return emplace_into_current_end (std::forward<Args> (args)...);
4412 :
4413 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
4414 : if (std::is_constant_evaluated ())
4415 : {
4416 : heap_temporary tmp (*this, std::forward<Args> (args)...);
4417 : shift_into_uninitialized (pos, 1);
4418 : *pos = tmp.release ();
4419 : return pos;
4420 : }
4421 : #endif
4422 :
4423 : // This is necessary because of possible aliasing.
4424 : stack_temporary tmp (*this, std::forward<Args> (args)...);
4425 : shift_into_uninitialized (pos, 1);
4426 : *pos = tmp.release ();
4427 : return pos;
4428 : }
4429 :
4430 : template <typename ...Args>
4431 : PLUMED_GCH_CPP20_CONSTEXPR
4432 : ptr
4433 1313 : emplace_into_reallocation_end (Args&&... args)
4434 : {
4435 : // Appending; strong exception guarantee.
4436 1313 : if (get_max_size () == get_size ())
4437 0 : throw_allocation_size_error ();
4438 :
4439 1313 : const size_ty new_size = get_size () + 1;
4440 :
4441 : // The check is handled by the if-guard.
4442 : const size_ty new_capacity = unchecked_calculate_new_capacity (new_size);
4443 1313 : const ptr new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
4444 1313 : const ptr emplace_pos = unchecked_next (new_data_ptr, get_size ());
4445 :
4446 : PLUMED_GCH_TRY
4447 : {
4448 : construct (emplace_pos, std::forward<Args> (args)...);
4449 : PLUMED_GCH_TRY
4450 : {
4451 1313 : uninitialized_move<strong_exception_policy> (begin_ptr (), end_ptr (), new_data_ptr);
4452 : }
4453 : PLUMED_GCH_CATCH (...)
4454 : {
4455 : destroy (emplace_pos);
4456 : PLUMED_GCH_THROW;
4457 : }
4458 : }
4459 : PLUMED_GCH_CATCH (...)
4460 : {
4461 : deallocate (new_data_ptr, new_capacity);
4462 : PLUMED_GCH_THROW;
4463 : }
4464 :
4465 : reset_data (new_data_ptr, new_capacity, new_size);
4466 1313 : return emplace_pos;
4467 : }
4468 :
4469 : template <typename ...Args>
4470 : PLUMED_GCH_CPP20_CONSTEXPR
4471 : ptr
4472 : emplace_into_reallocation (ptr pos, Args&&... args)
4473 : {
4474 : const size_ty offset = internal_range_length (begin_ptr (), pos);
4475 : if (offset == get_size ())
4476 : return emplace_into_reallocation_end (std::forward<Args> (args)...);
4477 :
4478 : if (get_max_size () == get_size ())
4479 : throw_allocation_size_error ();
4480 :
4481 : const size_ty new_size = get_size () + 1;
4482 :
4483 : // The check is handled by the if-guard.
4484 : const size_ty new_capacity = unchecked_calculate_new_capacity (new_size);
4485 : const ptr new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
4486 : ptr new_first = unchecked_next (new_data_ptr, offset);
4487 : ptr new_last = new_first;
4488 :
4489 : PLUMED_GCH_TRY
4490 : {
4491 : construct (new_first, std::forward<Args> (args)...);
4492 : unchecked_advance (new_last, 1);
4493 :
4494 : uninitialized_move (begin_ptr (), pos, new_data_ptr);
4495 : new_first = new_data_ptr;
4496 : uninitialized_move (pos, end_ptr (), new_last);
4497 : }
4498 : PLUMED_GCH_CATCH (...)
4499 : {
4500 : destroy_range (new_first, new_last);
4501 : deallocate (new_data_ptr, new_capacity);
4502 : PLUMED_GCH_THROW;
4503 : }
4504 :
4505 : reset_data (new_data_ptr, new_capacity, new_size);
4506 : return unchecked_next (begin_ptr (), offset);
4507 : }
4508 :
4509 : PLUMED_GCH_CPP20_CONSTEXPR
4510 : ptr
4511 : shrink_to_size (void)
4512 : {
4513 : if (! has_allocation () || get_size () == get_capacity ())
4514 : return begin_ptr ();
4515 :
4516 : // The rest runs only if allocated.
4517 :
4518 : size_ty new_capacity;
4519 : ptr new_data_ptr;
4520 :
4521 : if (InlineCapacity < get_size ())
4522 : {
4523 : new_capacity = get_size ();
4524 : new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
4525 : }
4526 : else
4527 : {
4528 : // We move to inline storage.
4529 : new_capacity = InlineCapacity;
4530 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
4531 : if (std::is_constant_evaluated ())
4532 : new_data_ptr = alloc_interface::allocate (InlineCapacity);
4533 : else
4534 : new_data_ptr = storage_ptr ();
4535 : #else
4536 : new_data_ptr = storage_ptr ();
4537 : #endif
4538 : }
4539 :
4540 : uninitialized_move (begin_ptr (), end_ptr (), new_data_ptr);
4541 :
4542 : destroy_range (begin_ptr (), end_ptr ());
4543 : deallocate (data_ptr (), get_capacity ());
4544 :
4545 : set_data_ptr (new_data_ptr);
4546 : set_capacity (new_capacity);
4547 :
4548 : return begin_ptr ();
4549 : }
4550 :
4551 : template <typename ...ValueT>
4552 : PLUMED_GCH_CPP20_CONSTEXPR
4553 : void
4554 : resize_with (size_ty new_size, const ValueT&... val)
4555 : {
4556 : // ValueT... should either be value_ty or empty.
4557 :
4558 : if (new_size == 0)
4559 : erase_all ();
4560 :
4561 : if (get_capacity () < new_size)
4562 : {
4563 : // Reallocate.
4564 :
4565 : if (get_max_size () < new_size)
4566 : throw_allocation_size_error ();
4567 :
4568 : const size_ty original_size = get_size ();
4569 :
4570 : // The check is handled by the if-guard.
4571 : const size_ty new_capacity = unchecked_calculate_new_capacity (new_size);
4572 : ptr new_data_ptr = unchecked_allocate (new_capacity, allocation_end_ptr ());
4573 : ptr new_last = unchecked_next (new_data_ptr, original_size);
4574 :
4575 : PLUMED_GCH_TRY
4576 : {
4577 : new_last = uninitialized_fill (
4578 : new_last,
4579 : unchecked_next (new_data_ptr, new_size),
4580 : val...);
4581 :
4582 : // Strong exception guarantee.
4583 : uninitialized_move<strong_exception_policy> (begin_ptr (), end_ptr (), new_data_ptr);
4584 : }
4585 : PLUMED_GCH_CATCH (...)
4586 : {
4587 : destroy_range (unchecked_next (new_data_ptr, original_size), new_last);
4588 : deallocate (new_data_ptr, new_capacity);
4589 : PLUMED_GCH_THROW;
4590 : }
4591 :
4592 : reset_data (new_data_ptr, new_capacity, new_size);
4593 : }
4594 : else if (get_size () < new_size)
4595 : {
4596 : // Construct in the uninitialized section.
4597 : uninitialized_fill (end_ptr (), unchecked_next (begin_ptr (), new_size), val...);
4598 : set_size (new_size);
4599 : }
4600 : else
4601 : erase_range (unchecked_next (begin_ptr (), new_size), end_ptr ());
4602 :
4603 : // Do nothing if the count is the same as the current size.
4604 : }
4605 :
4606 : PLUMED_GCH_CPP20_CONSTEXPR
4607 : void
4608 50163 : request_capacity (size_ty request)
4609 : {
4610 50163 : if (request <= get_capacity ())
4611 : return;
4612 :
4613 2344 : size_ty new_capacity = checked_calculate_new_capacity (request);
4614 : ptr new_begin = unchecked_allocate (new_capacity);
4615 :
4616 : PLUMED_GCH_TRY
4617 : {
4618 2344 : uninitialized_move<strong_exception_policy> (begin_ptr (), end_ptr (), new_begin);
4619 : }
4620 : PLUMED_GCH_CATCH (...)
4621 : {
4622 : deallocate (new_begin, new_capacity);
4623 : PLUMED_GCH_THROW;
4624 : }
4625 :
4626 2344 : wipe ();
4627 :
4628 : set_data_ptr (new_begin);
4629 : set_capacity (new_capacity);
4630 : }
4631 :
4632 : PLUMED_GCH_CPP20_CONSTEXPR
4633 : ptr
4634 : erase_at (ptr pos)
4635 : {
4636 : move_left (unchecked_next (pos), end_ptr (), pos);
4637 : erase_last ();
4638 : return pos;
4639 : }
4640 :
4641 : PLUMED_GCH_CPP20_CONSTEXPR
4642 : void
4643 : erase_last (void)
4644 : {
4645 : decrease_size (1);
4646 :
4647 : // The element located at end_ptr is still alive since the size decreased.
4648 137267 : destroy (end_ptr ());
4649 : }
4650 :
4651 : PLUMED_GCH_CPP20_CONSTEXPR
4652 : ptr
4653 : erase_range (ptr first, ptr last)
4654 : {
4655 : if (! (first == last))
4656 : erase_to_end (move_left (last, end_ptr (), first));
4657 : return first;
4658 : }
4659 :
4660 : PLUMED_GCH_CPP20_CONSTEXPR
4661 : void
4662 : erase_to_end (ptr pos)
4663 : {
4664 : assert (0 <= (end_ptr () - pos) && "`pos` was in the uninitialized range");
4665 : if (size_ty change = internal_range_length (pos, end_ptr ()))
4666 : {
4667 : decrease_size (change);
4668 : destroy_range (pos, unchecked_next (pos, change));
4669 : }
4670 : }
4671 :
4672 : PLUMED_GCH_CPP20_CONSTEXPR
4673 : void
4674 : erase_all (void)
4675 : {
4676 1509998 : ptr curr_end = end_ptr ();
4677 : set_size (0);
4678 : destroy_range (begin_ptr (), curr_end);
4679 : }
4680 :
4681 : PLUMED_GCH_CPP20_CONSTEXPR
4682 : void
4683 : swap_elements (small_vector_base& other)
4684 : noexcept (std::is_nothrow_move_constructible<value_ty>::value
4685 : #ifdef PLUMED_GCH_LIB_IS_SWAPPABLE
4686 : && std::is_nothrow_swappable<value_ty>::value
4687 : #else
4688 : && detail::small_vector_adl::is_nothrow_swappable<value_ty>::value
4689 : #endif
4690 : )
4691 : {
4692 : assert (get_size () <= other.get_size ());
4693 :
4694 : const ptr other_tail = std::swap_ranges (begin_ptr (), end_ptr (), other.begin_ptr ());
4695 : uninitialized_move (other_tail, other.end_ptr (), end_ptr ());
4696 : destroy_range (other_tail, other.end_ptr ());
4697 :
4698 : swap_size (other);
4699 : }
4700 :
4701 : PLUMED_GCH_CPP20_CONSTEXPR
4702 : void
4703 : swap_default (small_vector_base& other)
4704 : noexcept (std::is_nothrow_move_constructible<value_ty>::value
4705 : #ifdef PLUMED_GCH_LIB_IS_SWAPPABLE
4706 : && std::is_nothrow_swappable<value_ty>::value
4707 : #else
4708 : && detail::small_vector_adl::is_nothrow_swappable<value_ty>::value
4709 : #endif
4710 : )
4711 : {
4712 : // This function is used when:
4713 : // We are using the standard allocator.
4714 : // The allocators propagate and are equal.
4715 : // The allocators are always equal.
4716 : // The allocators do not propagate and are equal.
4717 : // The allocators propagate and are not equal.
4718 :
4719 : // Not handled:
4720 : // The allocators do not propagate and are not equal.
4721 :
4722 : assert (get_capacity () <= other.get_capacity ());
4723 :
4724 : if (has_allocation ()) // Implies that `other` also has an allocation.
4725 : swap_allocation (other);
4726 : else if (other.has_allocation ())
4727 : {
4728 : // Note: This will never be constant evaluated because both are always allocated.
4729 : uninitialized_move (begin_ptr (), end_ptr (), other.storage_ptr ());
4730 : destroy_range (begin_ptr (), end_ptr ());
4731 :
4732 : set_data_ptr (other.data_ptr ());
4733 : set_capacity (other.get_capacity ());
4734 :
4735 : other.set_data_ptr (other.storage_ptr ());
4736 : other.set_capacity (InlineCapacity);
4737 :
4738 : swap_size (other);
4739 : }
4740 : else if (get_size () < other.get_size ())
4741 : swap_elements (other);
4742 : else
4743 : other.swap_elements (*this);
4744 :
4745 : alloc_interface::swap (other);
4746 : }
4747 :
4748 : PLUMED_GCH_CPP20_CONSTEXPR
4749 : void
4750 : swap_unequal_no_propagate (small_vector_base& other)
4751 : {
4752 : assert (get_capacity () <= other.get_capacity ());
4753 :
4754 : if (get_capacity () < other.get_size ())
4755 : {
4756 : // Reallocation required.
4757 : // We should always be able to reuse the allocation of `other`.
4758 : const size_ty new_capacity = unchecked_calculate_new_capacity (other.get_size ());
4759 : const ptr new_data_ptr = unchecked_allocate (new_capacity, end_ptr ());
4760 :
4761 : PLUMED_GCH_TRY
4762 : {
4763 : uninitialized_move (other.begin_ptr (), other.end_ptr (), new_data_ptr);
4764 : PLUMED_GCH_TRY
4765 : {
4766 : destroy_range (
4767 : std::move (begin_ptr (), end_ptr (), other.begin_ptr ()),
4768 : other.end_ptr ());
4769 : }
4770 : PLUMED_GCH_CATCH (...)
4771 : {
4772 : destroy_range (new_data_ptr, unchecked_next (new_data_ptr, other.get_size ()));
4773 : PLUMED_GCH_THROW;
4774 : }
4775 : }
4776 : PLUMED_GCH_CATCH (...)
4777 : {
4778 : deallocate (new_data_ptr, new_capacity);
4779 : PLUMED_GCH_THROW;
4780 : }
4781 :
4782 : destroy_range (begin_ptr (), end_ptr ());
4783 : if (has_allocation ())
4784 : deallocate (data_ptr (), get_capacity ());
4785 :
4786 : set_data_ptr (new_data_ptr);
4787 : set_capacity (new_capacity);
4788 : swap_size (other);
4789 : }
4790 : else if (get_size () < other.get_size ())
4791 : swap_elements (other);
4792 : else
4793 : other.swap_elements (*this);
4794 :
4795 : // This should have no effect.
4796 : alloc_interface::swap (other);
4797 : }
4798 :
4799 : template <typename A = alloc_ty,
4800 : typename std::enable_if<allocations_are_swappable<A>::value
4801 : && InlineCapacity == 0>::type * = nullptr>
4802 : PLUMED_GCH_CPP20_CONSTEXPR
4803 : void
4804 : swap (small_vector_base& other) noexcept
4805 : {
4806 : swap_allocation (other);
4807 : alloc_interface::swap (other);
4808 : }
4809 :
4810 : template <typename A = alloc_ty,
4811 : typename std::enable_if<allocations_are_swappable<A>::value
4812 : && InlineCapacity != 0>::type * = nullptr>
4813 : PLUMED_GCH_CPP20_CONSTEXPR
4814 : void
4815 : swap (small_vector_base& other)
4816 : noexcept (std::is_nothrow_move_constructible<value_ty>::value
4817 : #ifdef PLUMED_GCH_LIB_IS_SWAPPABLE
4818 : && std::is_nothrow_swappable<value_ty>::value
4819 : #else
4820 : && detail::small_vector_adl::is_nothrow_swappable<value_ty>::value
4821 : #endif
4822 : )
4823 : {
4824 : if (get_capacity () < other.get_capacity ())
4825 : swap_default (other);
4826 : else
4827 : other.swap_default (*this);
4828 : }
4829 :
4830 : template <typename A = alloc_ty,
4831 : typename std::enable_if<! allocations_are_swappable<A>::value>::type * = nullptr>
4832 : PLUMED_GCH_CPP20_CONSTEXPR
4833 : void
4834 : swap (small_vector_base& other)
4835 : {
4836 : if (get_capacity () < other.get_capacity ())
4837 : {
4838 : if (other.allocator_ref () == allocator_ref ())
4839 : swap_default (other);
4840 : else
4841 : swap_unequal_no_propagate (other);
4842 : }
4843 : else
4844 : {
4845 : if (other.allocator_ref () == allocator_ref ())
4846 : other.swap_default (*this);
4847 : else
4848 : other.swap_unequal_no_propagate (*this);
4849 : }
4850 : }
4851 :
4852 : #ifdef __GLIBCXX__
4853 :
4854 : // These are compatibility fixes for libstdc++ because std::copy doesn't work for
4855 : // `move_iterator`s when constant evaluated.
4856 :
4857 : template <typename InputIt>
4858 : static PLUMED_GCH_CPP20_CONSTEXPR
4859 : InputIt
4860 : unmove_iterator (InputIt it)
4861 : {
4862 : return it;
4863 : }
4864 :
4865 : template <typename InputIt>
4866 : static PLUMED_GCH_CPP20_CONSTEXPR
4867 : auto
4868 : unmove_iterator (std::move_iterator<InputIt> it)
4869 : -> decltype (unmove_iterator (it.base ()))
4870 : {
4871 : return unmove_iterator (it.base ());
4872 : }
4873 :
4874 : template <typename InputIt>
4875 : static PLUMED_GCH_CPP20_CONSTEXPR
4876 : auto
4877 : unmove_iterator (std::reverse_iterator<InputIt> it)
4878 : -> std::reverse_iterator<decltype (unmove_iterator (it.base ()))>
4879 : {
4880 : return std::reverse_iterator<decltype (unmove_iterator (it.base ()))> (
4881 : unmove_iterator (it.base ()));
4882 : }
4883 :
4884 : #endif
4885 :
4886 : template <typename InputIt>
4887 : PLUMED_GCH_CPP20_CONSTEXPR
4888 : ptr
4889 : copy_range (InputIt first, InputIt last, ptr dest)
4890 : {
4891 : #if defined (PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED) && defined (__GLIBCXX__)
4892 : if ( std::is_constant_evaluated ()
4893 : &&! std::is_same<decltype (unmove_iterator (std::declval<InputIt> ())),
4894 : InputIt>::value)
4895 : {
4896 : return std::move (unmove_iterator (first), unmove_iterator (last), dest);
4897 : }
4898 : #endif
4899 :
4900 : return std::copy (first, last, dest);
4901 : }
4902 :
4903 : template <typename InputIt,
4904 : typename std::enable_if<
4905 : is_memcpyable_iterator<InputIt>::value>::type * = nullptr>
4906 : PLUMED_GCH_CPP20_CONSTEXPR
4907 : InputIt
4908 : copy_n_return_in (InputIt first, size_ty count, ptr dest) noexcept
4909 : {
4910 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
4911 : if (std::is_constant_evaluated ())
4912 : {
4913 : std::copy_n (first, count, dest);
4914 : return unchecked_next (first, count);
4915 : }
4916 : #endif
4917 :
4918 : if (count != 0)
4919 : std::memcpy (to_address (dest), to_address (first), count * sizeof (value_ty));
4920 : // Note: The unsafe cast here should be proven to be safe in the caller function.
4921 : return unchecked_next (first, count);
4922 : }
4923 :
4924 : template <typename InputIt,
4925 : typename std::enable_if<
4926 : is_memcpyable_iterator<InputIt>::value>::type * = nullptr>
4927 : PLUMED_GCH_CPP20_CONSTEXPR
4928 : std::move_iterator<InputIt>
4929 : copy_n_return_in (std::move_iterator<InputIt> first, size_ty count, ptr dest) noexcept
4930 : {
4931 : return std::move_iterator<InputIt> (copy_n_return_in (first.base (), count, dest));
4932 : }
4933 :
4934 : template <typename RandomIt,
4935 : typename std::enable_if<
4936 : ! is_memcpyable_iterator<RandomIt>::value
4937 : && std::is_base_of<std::random_access_iterator_tag,
4938 : typename std::iterator_traits<RandomIt>::iterator_category>::value
4939 : >::type * = nullptr>
4940 : PLUMED_GCH_CPP20_CONSTEXPR
4941 : RandomIt
4942 : copy_n_return_in (RandomIt first, size_ty count, ptr dest)
4943 : {
4944 : #if defined (PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED) && defined (__GLIBCXX__)
4945 : if ( std::is_constant_evaluated ()
4946 : &&! std::is_same<decltype (unmove_iterator (std::declval<RandomIt> ())),
4947 : RandomIt>::value)
4948 : {
4949 : auto bfirst = unmove_iterator (first);
4950 : auto blast = unchecked_next (bfirst, count);
4951 : std::move (bfirst, blast, dest);
4952 : return unchecked_next (first, count);
4953 : }
4954 : #endif
4955 :
4956 : std::copy_n (first, count, dest);
4957 : // Note: This unsafe cast should be proven safe in the caller function.
4958 : return unchecked_next (first, count);
4959 : }
4960 :
4961 : template <typename InputIt,
4962 : typename std::enable_if<
4963 : ! is_memcpyable_iterator<InputIt>::value
4964 : &&! std::is_base_of<std::random_access_iterator_tag,
4965 : typename std::iterator_traits<InputIt>::iterator_category>::value
4966 : >::type * = nullptr>
4967 : PLUMED_GCH_CPP20_CONSTEXPR
4968 : InputIt
4969 : copy_n_return_in (InputIt first, size_ty count, ptr dest)
4970 : {
4971 :
4972 : for (; count != 0; --count, static_cast<void> (++dest), static_cast<void> (++first))
4973 : *dest = *first;
4974 : return first;
4975 : }
4976 :
4977 : template <typename V = value_ty,
4978 : typename std::enable_if<is_memcpyable<V>::value>::type * = nullptr>
4979 : PLUMED_GCH_CPP20_CONSTEXPR
4980 : ptr
4981 : move_left (ptr first, ptr last, ptr d_first)
4982 : {
4983 : // Shift initialized elements to the left.
4984 :
4985 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
4986 : if (std::is_constant_evaluated ())
4987 : return std::move (first, last, d_first);
4988 : #endif
4989 :
4990 : const size_ty num_moved = internal_range_length (first, last);
4991 : if (num_moved != 0)
4992 : std::memmove (to_address (d_first), to_address (first), num_moved * sizeof (value_ty));
4993 : return unchecked_next (d_first, num_moved);
4994 : }
4995 :
4996 : template <typename V = value_ty,
4997 : typename std::enable_if<! is_memcpyable<V>::value>::type * = nullptr>
4998 : PLUMED_GCH_CPP20_CONSTEXPR
4999 : ptr
5000 : move_left (ptr first, ptr last, ptr d_first)
5001 : {
5002 : // Shift initialized elements to the left.
5003 : return std::move (first, last, d_first);
5004 : }
5005 :
5006 : template <typename V = value_ty,
5007 : typename std::enable_if<is_memcpyable<V>::value, bool>::type = true>
5008 : PLUMED_GCH_CPP20_CONSTEXPR
5009 : ptr
5010 : move_right (ptr first, ptr last, ptr d_last)
5011 : {
5012 : // Move initialized elements to the right.
5013 :
5014 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
5015 : if (std::is_constant_evaluated ())
5016 : return std::move_backward (first, last, d_last);
5017 : #endif
5018 :
5019 : const size_ty num_moved = internal_range_length (first, last);
5020 : const ptr dest = unchecked_prev (d_last, num_moved);
5021 : if (num_moved != 0)
5022 : std::memmove (to_address (dest), to_address (first), num_moved * sizeof (value_ty));
5023 : return dest;
5024 : }
5025 :
5026 : template <typename V = value_ty,
5027 : typename std::enable_if<! is_memcpyable<V>::value, bool>::type = false>
5028 : PLUMED_GCH_CPP20_CONSTEXPR
5029 : ptr
5030 : move_right (ptr first, ptr last, ptr d_last)
5031 : {
5032 : // move initialized elements to the right
5033 : // n should not be 0
5034 : return std::move_backward (first, last, d_last);
5035 : }
5036 :
5037 : public:
5038 : PLUMED_GCH_CPP20_CONSTEXPR
5039 : void
5040 : set_default (void)
5041 : {
5042 : set_to_inline_storage ();
5043 : set_size (0);
5044 : }
5045 :
5046 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
5047 : ptr
5048 : data_ptr (void) noexcept
5049 : {
5050 : return m_data.data_ptr ();
5051 : }
5052 :
5053 : PLUMED_GCH_NODISCARD constexpr
5054 : cptr
5055 : data_ptr (void) const noexcept
5056 : {
5057 : return m_data.data_ptr ();
5058 : }
5059 :
5060 : PLUMED_GCH_NODISCARD constexpr
5061 : size_ty
5062 : get_capacity (void) const noexcept
5063 : {
5064 : return m_data.capacity ();
5065 : }
5066 :
5067 : PLUMED_GCH_NODISCARD constexpr
5068 : size_ty
5069 : get_size (void) const noexcept
5070 : {
5071 : return m_data.size ();
5072 : }
5073 :
5074 : PLUMED_GCH_NODISCARD constexpr
5075 : size_ty
5076 : num_uninitialized (void) const noexcept
5077 : {
5078 : return get_capacity () - get_size ();
5079 : }
5080 :
5081 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
5082 : ptr
5083 : begin_ptr (void) noexcept
5084 : {
5085 : return data_ptr ();
5086 : }
5087 :
5088 : PLUMED_GCH_NODISCARD
5089 : constexpr
5090 : cptr
5091 : begin_ptr (void) const noexcept
5092 : {
5093 : return data_ptr ();
5094 : }
5095 :
5096 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
5097 : ptr
5098 16733731 : end_ptr (void) noexcept
5099 : {
5100 16733731 : return unchecked_next (begin_ptr (), get_size ());
5101 : }
5102 :
5103 : PLUMED_GCH_NODISCARD constexpr
5104 : cptr
5105 4208848 : end_ptr (void) const noexcept
5106 : {
5107 4208848 : return unchecked_next (begin_ptr (), get_size ());
5108 : }
5109 :
5110 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
5111 : ptr
5112 1313 : allocation_end_ptr (void) noexcept
5113 : {
5114 1313 : return unchecked_next (begin_ptr (), get_capacity ());
5115 : }
5116 :
5117 : PLUMED_GCH_NODISCARD constexpr
5118 : cptr
5119 0 : allocation_end_ptr (void) const noexcept
5120 : {
5121 0 : return unchecked_next (begin_ptr (), get_capacity ());
5122 : }
5123 :
5124 : PLUMED_GCH_NODISCARD constexpr
5125 : alloc_ty
5126 : copy_allocator (void) const noexcept
5127 : {
5128 : return alloc_ty (allocator_ref ());
5129 : }
5130 :
5131 : PLUMED_GCH_NODISCARD PLUMED_GCH_CPP14_CONSTEXPR
5132 : ptr
5133 : storage_ptr (void) noexcept
5134 : {
5135 : return m_data.storage ();
5136 : }
5137 :
5138 : PLUMED_GCH_NODISCARD constexpr
5139 : cptr
5140 : storage_ptr (void) const noexcept
5141 : {
5142 : return m_data.storage ();
5143 : }
5144 :
5145 : PLUMED_GCH_NODISCARD constexpr
5146 : bool
5147 : has_allocation (void) const noexcept
5148 : {
5149 : #ifdef PLUMED_GCH_LIB_IS_CONSTANT_EVALUATED
5150 : if (std::is_constant_evaluated ())
5151 : return true;
5152 : #endif
5153 : return InlineCapacity < get_capacity ();
5154 : }
5155 :
5156 : PLUMED_GCH_NODISCARD constexpr
5157 : bool
5158 : is_inlinable (void) const noexcept
5159 : {
5160 : return get_size () <= InlineCapacity;
5161 : }
5162 :
5163 : private:
5164 : small_vector_data<ptr, size_type, value_ty, InlineCapacity> m_data;
5165 : };
5166 :
5167 : } // namespace gch::detail
5168 :
5169 : template <typename T, unsigned InlineCapacity, typename Allocator>
5170 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5171 : requires concepts::small_vector::AllocatorFor<Allocator, T>
5172 : #endif
5173 : class small_vector
5174 : : private detail::small_vector_base<Allocator, InlineCapacity>
5175 : {
5176 : using base = detail::small_vector_base<Allocator, InlineCapacity>;
5177 :
5178 : public:
5179 : static_assert (std::is_same<T, typename Allocator::value_type>::value,
5180 : "`Allocator::value_type` must be the same as `T`.");
5181 :
5182 : template <typename SameT, unsigned DifferentInlineCapacity, typename SameAllocator>
5183 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5184 : requires concepts::small_vector::AllocatorFor<SameAllocator, SameT>
5185 : #endif
5186 : friend class small_vector;
5187 :
5188 : using value_type = T;
5189 : using allocator_type = Allocator;
5190 : using size_type = typename base::size_type;
5191 : using difference_type = typename base::difference_type;
5192 : using reference = value_type&;
5193 : using const_reference = const value_type&;
5194 : using pointer = typename std::allocator_traits<allocator_type>::pointer;
5195 : using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
5196 :
5197 : using iterator = small_vector_iterator<pointer, difference_type>;
5198 : using const_iterator = small_vector_iterator<const_pointer, difference_type>;
5199 : using reverse_iterator = std::reverse_iterator<iterator>;
5200 : using const_reverse_iterator = std::reverse_iterator<const_iterator>;
5201 :
5202 : static_assert (InlineCapacity <= (std::numeric_limits<size_type>::max) (),
5203 : "InlineCapacity must be less than or equal to the maximum value of size_type.");
5204 :
5205 : static constexpr
5206 : unsigned
5207 : inline_capacity_v = InlineCapacity;
5208 :
5209 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5210 :
5211 : private:
5212 : static constexpr
5213 : bool
5214 : Destructible = concepts::small_vector::Destructible<value_type>;
5215 :
5216 : static constexpr
5217 : bool
5218 : MoveAssignable = concepts::small_vector::MoveAssignable<value_type>;
5219 :
5220 : static constexpr
5221 : bool
5222 : CopyAssignable = concepts::small_vector::CopyAssignable<value_type>;
5223 :
5224 : static constexpr
5225 : bool
5226 : MoveConstructible = concepts::small_vector::MoveConstructible<value_type>;
5227 :
5228 : static constexpr
5229 : bool
5230 : CopyConstructible = concepts::small_vector::CopyConstructible<value_type>;
5231 :
5232 : static constexpr
5233 : bool
5234 : Swappable = concepts::small_vector::Swappable<value_type>;
5235 :
5236 : static constexpr
5237 : bool
5238 : DefaultInsertable = concepts::small_vector::DefaultInsertable<value_type, small_vector,
5239 : allocator_type>;
5240 :
5241 : static constexpr
5242 : bool
5243 : MoveInsertable = concepts::small_vector::MoveInsertable<value_type, small_vector,
5244 : allocator_type>;
5245 :
5246 : static constexpr
5247 : bool
5248 : CopyInsertable = concepts::small_vector::CopyInsertable<value_type, small_vector,
5249 : allocator_type>;
5250 :
5251 : static constexpr
5252 : bool
5253 : Erasable = concepts::small_vector::Erasable<value_type, small_vector, allocator_type>;
5254 :
5255 : template <typename ...Args>
5256 : struct EmplaceConstructible
5257 : {
5258 : static constexpr
5259 : bool
5260 : value = concepts::small_vector::EmplaceConstructible<value_type, small_vector,
5261 : allocator_type, Args...>;
5262 : };
5263 :
5264 : public:
5265 :
5266 : #endif
5267 :
5268 : PLUMED_GCH_CPP20_CONSTEXPR
5269 : small_vector (void)
5270 : noexcept (noexcept (allocator_type ()))
5271 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5272 : requires concepts::DefaultConstructible<allocator_type>
5273 : #endif
5274 : = default;
5275 :
5276 : PLUMED_GCH_CPP20_CONSTEXPR
5277 : small_vector (const small_vector& other)
5278 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5279 : requires CopyInsertable
5280 : #endif
5281 : : base (base::bypass, other)
5282 : { }
5283 :
5284 : PLUMED_GCH_CPP20_CONSTEXPR
5285 : small_vector (small_vector&& other)
5286 : noexcept (std::is_nothrow_move_constructible<value_type>::value || InlineCapacity == 0)
5287 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5288 : requires MoveInsertable
5289 : #endif
5290 : : base (base::bypass, std::move (other))
5291 : { }
5292 :
5293 : PLUMED_GCH_CPP20_CONSTEXPR explicit
5294 : small_vector (const allocator_type& alloc) noexcept
5295 : : base (alloc)
5296 : { }
5297 :
5298 : PLUMED_GCH_CPP20_CONSTEXPR
5299 : small_vector (const small_vector& other, const allocator_type& alloc)
5300 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5301 : requires CopyInsertable
5302 : #endif
5303 : : base (base::bypass, other, alloc)
5304 : { }
5305 :
5306 : PLUMED_GCH_CPP20_CONSTEXPR
5307 : small_vector (small_vector&& other, const allocator_type& alloc)
5308 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5309 : requires MoveInsertable
5310 : #endif
5311 : : base (base::bypass, std::move (other), alloc)
5312 : { }
5313 :
5314 : PLUMED_GCH_CPP20_CONSTEXPR explicit
5315 3738 : small_vector (size_type count, const allocator_type& alloc = allocator_type ())
5316 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5317 : requires DefaultInsertable
5318 : #endif
5319 3738 : : base (count, alloc)
5320 : { }
5321 :
5322 : PLUMED_GCH_CPP20_CONSTEXPR
5323 : small_vector (size_type count, const_reference value,
5324 : const allocator_type& alloc = allocator_type ())
5325 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5326 : requires CopyInsertable
5327 : #endif
5328 : : base (count, value, alloc)
5329 : { }
5330 :
5331 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5332 : template <typename Generator>
5333 : requires std::invocable<Generator&>
5334 : && EmplaceConstructible<std::invoke_result_t<Generator&>>::value
5335 : #else
5336 : template <typename Generator,
5337 : typename std::enable_if<
5338 : ! std::is_convertible<Generator, const_reference>::value>::type * = nullptr>
5339 : #endif
5340 : PLUMED_GCH_CPP20_CONSTEXPR
5341 : small_vector (size_type count, Generator g, const allocator_type& alloc = allocator_type ())
5342 : : base (count, g, alloc)
5343 : { }
5344 :
5345 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5346 : template <std::input_iterator InputIt>
5347 : requires EmplaceConstructible<std::iter_reference_t<InputIt>>::value
5348 : && (std::forward_iterator<InputIt> || MoveInsertable)
5349 : #else
5350 : template <typename InputIt,
5351 : typename std::enable_if<
5352 : std::is_base_of<
5353 : std::input_iterator_tag,
5354 : typename std::iterator_traits<InputIt>::iterator_category>::value
5355 : >::type * = nullptr>
5356 : #endif
5357 : PLUMED_GCH_CPP20_CONSTEXPR
5358 : small_vector (InputIt first, InputIt last, const allocator_type& alloc = allocator_type ())
5359 : : base (first, last, typename std::iterator_traits<InputIt>::iterator_category { }, alloc)
5360 : { }
5361 :
5362 : PLUMED_GCH_CPP20_CONSTEXPR
5363 : small_vector (std::initializer_list<value_type> init,
5364 : const allocator_type& alloc = allocator_type ())
5365 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5366 : requires EmplaceConstructible<const_reference>::value
5367 : #endif
5368 : : small_vector (init.begin (), init.end (), alloc)
5369 : { }
5370 :
5371 : template <unsigned I>
5372 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5373 : requires CopyInsertable
5374 : #endif
5375 : PLUMED_GCH_CPP20_CONSTEXPR explicit
5376 : small_vector (const small_vector<T, I, Allocator>& other)
5377 : : base (base::bypass, other)
5378 : { }
5379 :
5380 : template <unsigned I>
5381 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5382 : requires MoveInsertable
5383 : #endif
5384 : PLUMED_GCH_CPP20_CONSTEXPR explicit
5385 : small_vector (small_vector<T, I, Allocator>&& other)
5386 : noexcept (std::is_nothrow_move_constructible<value_type>::value && I < InlineCapacity)
5387 : : base (base::bypass, std::move (other))
5388 : { }
5389 :
5390 : template <unsigned I>
5391 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5392 : requires CopyInsertable
5393 : #endif
5394 : PLUMED_GCH_CPP20_CONSTEXPR
5395 : small_vector (const small_vector<T, I, Allocator>& other, const allocator_type& alloc)
5396 : : base (base::bypass, other, alloc)
5397 : { }
5398 :
5399 : template <unsigned I>
5400 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5401 : requires MoveInsertable
5402 : #endif
5403 : PLUMED_GCH_CPP20_CONSTEXPR
5404 : small_vector (small_vector<T, I, Allocator>&& other, const allocator_type& alloc)
5405 : : base (base::bypass, std::move (other), alloc)
5406 : { }
5407 :
5408 : PLUMED_GCH_CPP20_CONSTEXPR
5409 1428222 : ~small_vector (void)
5410 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5411 : requires Erasable
5412 : #endif
5413 : = default;
5414 :
5415 : PLUMED_GCH_CPP20_CONSTEXPR
5416 : small_vector&
5417 : operator= (const small_vector& other)
5418 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5419 : requires CopyInsertable && CopyAssignable
5420 : #endif
5421 : {
5422 : assign (other);
5423 : return *this;
5424 : }
5425 :
5426 : PLUMED_GCH_CPP20_CONSTEXPR
5427 : small_vector&
5428 : operator= (small_vector&& other)
5429 : noexcept ( ( std::is_same<std::allocator<value_type>, Allocator>::value
5430 : || std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value
5431 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
5432 : || std::allocator_traits<Allocator>::is_always_equal::value
5433 : #endif
5434 : )
5435 : && ( ( std::is_nothrow_move_assignable<value_type>::value
5436 : && std::is_nothrow_move_constructible<value_type>::value
5437 : )
5438 : || InlineCapacity == 0
5439 : )
5440 : )
5441 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5442 : // Note: The standard says here that
5443 : // std::allocator_traits<allocator_type>::propagate_on_container_move_assignment == false
5444 : // implies MoveInsertable && MoveAssignable, but since we have inline storage we must always
5445 : // require moves [tab:container.alloc.req].
5446 : requires MoveInsertable && MoveAssignable
5447 : #endif
5448 : {
5449 : assign (std::move (other));
5450 : return *this;
5451 : }
5452 :
5453 : PLUMED_GCH_CPP20_CONSTEXPR
5454 : small_vector&
5455 : operator= (std::initializer_list<value_type> ilist)
5456 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5457 : requires CopyInsertable && CopyAssignable
5458 : #endif
5459 : {
5460 : assign (ilist);
5461 : return *this;
5462 : }
5463 :
5464 : PLUMED_GCH_CPP20_CONSTEXPR
5465 : void
5466 : assign (size_type count, const_reference value)
5467 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5468 : requires CopyInsertable && CopyAssignable
5469 : #endif
5470 : {
5471 : base::assign_with_copies (count, value);
5472 : }
5473 :
5474 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5475 : template <std::input_iterator InputIt>
5476 : requires EmplaceConstructible<std::iter_reference_t<InputIt>>::value
5477 : && (std::forward_iterator<InputIt> || MoveInsertable)
5478 : #else
5479 : template <typename InputIt,
5480 : typename std::enable_if<std::is_base_of<
5481 : std::input_iterator_tag,
5482 : typename std::iterator_traits<InputIt>::iterator_category
5483 : >::value>::type * = nullptr>
5484 : #endif
5485 : PLUMED_GCH_CPP20_CONSTEXPR
5486 : void
5487 : assign (InputIt first, InputIt last)
5488 : {
5489 : using iterator_cat = typename std::iterator_traits<InputIt>::iterator_category;
5490 : base::assign_with_range (first, last, iterator_cat { });
5491 : }
5492 :
5493 : PLUMED_GCH_CPP20_CONSTEXPR
5494 : void
5495 : assign (std::initializer_list<value_type> ilist)
5496 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5497 : requires EmplaceConstructible<const_reference>::value
5498 : #endif
5499 : {
5500 : assign (ilist.begin (), ilist.end ());
5501 : }
5502 :
5503 : PLUMED_GCH_CPP20_CONSTEXPR
5504 : void
5505 : assign (const small_vector& other)
5506 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5507 : requires CopyInsertable && CopyAssignable
5508 : #endif
5509 : {
5510 : if (&other != this)
5511 : base::copy_assign (other);
5512 : }
5513 :
5514 : template <unsigned I>
5515 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5516 : requires CopyInsertable && CopyAssignable
5517 : #endif
5518 : PLUMED_GCH_CPP20_CONSTEXPR
5519 : void
5520 : assign (const small_vector<T, I, Allocator>& other)
5521 : {
5522 : base::copy_assign (other);
5523 : }
5524 :
5525 : PLUMED_GCH_CPP20_CONSTEXPR
5526 : void
5527 : assign (small_vector&& other)
5528 : noexcept ( ( std::is_same<std::allocator<value_type>, Allocator>::value
5529 : || std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value
5530 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
5531 : || std::allocator_traits<Allocator>::is_always_equal::value
5532 : #endif
5533 : )
5534 : && ( ( std::is_nothrow_move_assignable<value_type>::value
5535 : && std::is_nothrow_move_constructible<value_type>::value
5536 : )
5537 : || InlineCapacity == 0
5538 : )
5539 : )
5540 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5541 : requires MoveInsertable && MoveAssignable
5542 : #endif
5543 : {
5544 : if (&other != this)
5545 : base::move_assign (std::move (other));
5546 : }
5547 :
5548 : template <unsigned I>
5549 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5550 : requires MoveInsertable && MoveAssignable
5551 : #endif
5552 : PLUMED_GCH_CPP20_CONSTEXPR
5553 : void
5554 : assign (small_vector<T, I, Allocator>&& other)
5555 : noexcept ( I <= InlineCapacity
5556 : && ( std::is_same<std::allocator<value_type>, Allocator>::value
5557 : || std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value
5558 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
5559 : || std::allocator_traits<Allocator>::is_always_equal::value
5560 : #endif
5561 : )
5562 : && std::is_nothrow_move_assignable<value_type>::value
5563 : && std::is_nothrow_move_constructible<value_type>::value
5564 : )
5565 : {
5566 : base::move_assign (std::move (other));
5567 : }
5568 :
5569 : #ifndef PLUMED_GCH_LIB_CONCEPTS
5570 : template <typename ValueType = value_type,
5571 : typename std::enable_if<
5572 : ( std::is_move_constructible<ValueType>::value
5573 : && std::is_move_assignable<ValueType>::value
5574 : #ifdef PLUMED_GCH_LIB_IS_SWAPPABLE
5575 : && std::is_swappable<ValueType>::value
5576 : #endif
5577 : )
5578 : || ( ( std::is_same<std::allocator<value_type>, Allocator>::value
5579 : || std::allocator_traits<Allocator>::propagate_on_container_swap::value
5580 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
5581 : || std::allocator_traits<Allocator>::is_always_equal::value
5582 : #endif
5583 : )
5584 : && InlineCapacity == 0
5585 : )
5586 : >::type * = nullptr>
5587 : #endif
5588 : PLUMED_GCH_CPP20_CONSTEXPR
5589 : void
5590 : swap (small_vector& other)
5591 : noexcept ( ( std::is_same<std::allocator<value_type>, Allocator>::value
5592 : || std::allocator_traits<Allocator>::propagate_on_container_swap::value
5593 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
5594 : || std::allocator_traits<Allocator>::is_always_equal::value
5595 : #endif
5596 : )
5597 : && ( ( std::is_nothrow_move_constructible<value_type>::value
5598 : && std::is_nothrow_move_assignable<value_type>::value
5599 : #ifdef PLUMED_GCH_LIB_IS_SWAPPABLE
5600 : && std::is_nothrow_swappable<value_type>::value
5601 : #else
5602 : && detail::small_vector_adl::is_nothrow_swappable<value_type>::value
5603 : #endif
5604 : )
5605 : || InlineCapacity == 0
5606 : )
5607 : )
5608 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5609 : requires (MoveInsertable && MoveAssignable && Swappable)
5610 : || ( ( std::is_same<std::allocator<value_type>, Allocator>::value
5611 : || std::allocator_traits<Allocator>::propagate_on_container_swap::value
5612 : #ifdef PLUMED_GCH_LIB_IS_ALWAYS_EQUAL
5613 : || std::allocator_traits<Allocator>::is_always_equal::value
5614 : #endif
5615 : )
5616 : && InlineCapacity == 0
5617 : )
5618 : #endif
5619 : {
5620 : base::swap (other);
5621 : }
5622 :
5623 : PLUMED_GCH_CPP14_CONSTEXPR
5624 : iterator
5625 : begin (void) noexcept
5626 : {
5627 : return iterator { base::begin_ptr () };
5628 : }
5629 :
5630 : constexpr
5631 : const_iterator
5632 : begin (void) const noexcept
5633 : {
5634 : return const_iterator { base::begin_ptr () };
5635 : }
5636 :
5637 : constexpr
5638 : const_iterator
5639 : cbegin (void) const noexcept
5640 : {
5641 : return begin ();
5642 : }
5643 :
5644 : PLUMED_GCH_CPP14_CONSTEXPR
5645 : iterator
5646 : end (void) noexcept
5647 : {
5648 4957660 : return iterator { base::end_ptr () };
5649 : }
5650 :
5651 : constexpr
5652 : const_iterator
5653 : end (void) const noexcept
5654 : {
5655 : return const_iterator { base::end_ptr () };
5656 : }
5657 :
5658 : constexpr
5659 : const_iterator
5660 : cend (void) const noexcept
5661 : {
5662 : return end ();
5663 : }
5664 :
5665 : PLUMED_GCH_CPP14_CONSTEXPR
5666 : reverse_iterator
5667 : rbegin (void) noexcept
5668 : {
5669 : return reverse_iterator { end () };
5670 : }
5671 :
5672 : constexpr
5673 : const_reverse_iterator
5674 : rbegin (void) const noexcept
5675 : {
5676 : return const_reverse_iterator { end () };
5677 : }
5678 :
5679 : constexpr
5680 : const_reverse_iterator
5681 : crbegin (void) const noexcept
5682 : {
5683 : return rbegin ();
5684 : }
5685 :
5686 : PLUMED_GCH_CPP14_CONSTEXPR
5687 : reverse_iterator
5688 : rend (void) noexcept
5689 : {
5690 : return reverse_iterator { begin () };
5691 : }
5692 :
5693 : constexpr
5694 : const_reverse_iterator
5695 : rend (void) const noexcept
5696 : {
5697 : return const_reverse_iterator { begin () };
5698 : }
5699 :
5700 : constexpr
5701 : const_reverse_iterator
5702 : crend (void) const noexcept
5703 : {
5704 : return rend ();
5705 : }
5706 :
5707 : PLUMED_GCH_CPP14_CONSTEXPR
5708 : reference
5709 : at (size_type pos)
5710 : {
5711 : if (size () <= pos)
5712 : base::throw_index_error ();
5713 : return begin ()[static_cast<difference_type> (pos)];
5714 : }
5715 :
5716 : PLUMED_GCH_CPP14_CONSTEXPR
5717 : const_reference
5718 : at (size_type pos) const
5719 : {
5720 : if (size () <= pos)
5721 : base::throw_index_error ();
5722 : return begin ()[static_cast<difference_type> (pos)];
5723 : }
5724 :
5725 : PLUMED_GCH_CPP14_CONSTEXPR
5726 : reference
5727 : operator[] (size_type pos)
5728 : {
5729 : #ifdef _GLIBCXX_DEBUG
5730 : if (size () <= pos) base::throw_index_error ();
5731 : #endif
5732 : return begin ()[static_cast<difference_type> (pos)];
5733 : }
5734 :
5735 : constexpr
5736 : const_reference
5737 : operator[] (size_type pos) const
5738 : {
5739 : #ifdef _GLIBCXX_DEBUG
5740 : if (size () <= pos) base::throw_index_error ();
5741 : #endif
5742 : return begin ()[static_cast<difference_type> (pos)];
5743 : }
5744 :
5745 : PLUMED_GCH_CPP14_CONSTEXPR
5746 : reference
5747 : front (void)
5748 : {
5749 : return (*this)[0];
5750 : }
5751 :
5752 : constexpr
5753 : const_reference
5754 : front (void) const
5755 : {
5756 : return (*this)[0];
5757 : }
5758 :
5759 : PLUMED_GCH_CPP14_CONSTEXPR
5760 : reference
5761 : back (void)
5762 : {
5763 2523923 : return (*this)[size () - 1];
5764 : }
5765 :
5766 : constexpr
5767 : const_reference
5768 : back (void) const
5769 : {
5770 : return (*this)[size () - 1];
5771 : }
5772 :
5773 : PLUMED_GCH_CPP14_CONSTEXPR
5774 : pointer
5775 : data (void) noexcept
5776 : {
5777 : return base::begin_ptr ();
5778 : }
5779 :
5780 : constexpr
5781 : const_pointer
5782 : data (void) const noexcept
5783 : {
5784 : return base::begin_ptr ();
5785 : }
5786 :
5787 : constexpr
5788 : size_type
5789 : size (void) const noexcept
5790 : {
5791 : return static_cast<size_type> (base::get_size ());
5792 : }
5793 :
5794 : PLUMED_GCH_NODISCARD constexpr
5795 : bool
5796 : empty (void) const noexcept
5797 : {
5798 : return size () == 0;
5799 : }
5800 :
5801 : PLUMED_GCH_CPP14_CONSTEXPR
5802 : size_type
5803 : max_size (void) const noexcept
5804 : {
5805 : return static_cast<size_type> (base::get_max_size ());
5806 : }
5807 :
5808 : constexpr
5809 : size_type
5810 : capacity (void) const noexcept
5811 : {
5812 : return static_cast<size_type> (base::get_capacity ());
5813 : }
5814 :
5815 : constexpr
5816 : allocator_type
5817 : get_allocator (void) const noexcept
5818 : {
5819 : return base::copy_allocator ();
5820 : }
5821 :
5822 : PLUMED_GCH_CPP20_CONSTEXPR
5823 : iterator
5824 : insert (const_iterator pos, const_reference value)
5825 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5826 : requires CopyInsertable && CopyAssignable
5827 : #endif
5828 : {
5829 : return emplace (pos, value);
5830 : }
5831 :
5832 : PLUMED_GCH_CPP20_CONSTEXPR
5833 : iterator
5834 : insert (const_iterator pos, value_type&& value)
5835 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5836 : requires MoveInsertable && MoveAssignable
5837 : #endif
5838 : {
5839 : return emplace (pos, std::move (value));
5840 : }
5841 :
5842 : PLUMED_GCH_CPP20_CONSTEXPR
5843 : iterator
5844 : insert (const_iterator pos, size_type count, const_reference value)
5845 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5846 : requires CopyInsertable && CopyAssignable
5847 : #endif
5848 : {
5849 : return iterator (base::insert_copies (base::ptr_cast (pos), count, value));
5850 : }
5851 :
5852 : // Note: Unlike std::vector, this does not require MoveConstructible because we
5853 : // don't use std::rotate (as was the reason for the change in C++17).
5854 : // Relevant: https://cplusplus.github.io/LWG/issue2266).
5855 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5856 : template <std::input_iterator InputIt>
5857 : requires EmplaceConstructible<std::iter_reference_t<InputIt>>::value
5858 : && MoveInsertable
5859 : && MoveAssignable
5860 : #else
5861 : template <typename InputIt,
5862 : typename std::enable_if<std::is_base_of<
5863 : std::input_iterator_tag,
5864 : typename std::iterator_traits<InputIt>::iterator_category
5865 : >::value>::type * = nullptr>
5866 : #endif
5867 : PLUMED_GCH_CPP20_CONSTEXPR
5868 : iterator
5869 : insert (const_iterator pos, InputIt first, InputIt last)
5870 : {
5871 : if (first == last)
5872 : return iterator (base::ptr_cast (pos));
5873 :
5874 : using iterator_cat = typename std::iterator_traits<InputIt>::iterator_category;
5875 : return iterator (base::insert_range (base::ptr_cast (pos), first, last, iterator_cat { }));
5876 : }
5877 :
5878 : PLUMED_GCH_CPP20_CONSTEXPR
5879 : iterator
5880 : insert (const_iterator pos, std::initializer_list<value_type> ilist)
5881 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5882 : requires EmplaceConstructible<const_reference>::value
5883 : && MoveInsertable
5884 : && MoveAssignable
5885 : #endif
5886 : {
5887 : return insert (pos, ilist.begin (), ilist.end ());
5888 : }
5889 :
5890 : template <typename ...Args>
5891 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5892 : requires EmplaceConstructible<Args...>::value
5893 : && MoveInsertable
5894 : && MoveAssignable
5895 : #endif
5896 : PLUMED_GCH_CPP20_CONSTEXPR
5897 : iterator
5898 : emplace (const_iterator pos, Args&&... args)
5899 : {
5900 : return iterator (base::emplace_at (base::ptr_cast (pos), std::forward<Args> (args)...));
5901 : }
5902 :
5903 : PLUMED_GCH_CPP20_CONSTEXPR
5904 : iterator
5905 : erase (const_iterator pos)
5906 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5907 : requires MoveAssignable && Erasable
5908 : #endif
5909 : {
5910 : assert (0 <= (pos - begin ()) && "`pos` is out of bounds (before `begin ()`)." );
5911 : assert (0 < (end () - pos) && "`pos` is out of bounds (at or after `end ()`).");
5912 :
5913 : return iterator (base::erase_at (base::ptr_cast (pos)));
5914 : }
5915 :
5916 : PLUMED_GCH_CPP20_CONSTEXPR
5917 : iterator
5918 : erase (const_iterator first, const_iterator last)
5919 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5920 : requires MoveAssignable && Erasable
5921 : #endif
5922 : {
5923 : assert (0 <= (last - first) && "Invalid range.");
5924 : assert (0 <= (first - begin ()) && "`first` is out of bounds (before `begin ()`)." );
5925 : assert (0 <= (end () - last) && "`last` is out of bounds (after `end ()`).");
5926 :
5927 : return iterator (base::erase_range (base::ptr_cast (first), base::ptr_cast (last)));
5928 : }
5929 :
5930 : PLUMED_GCH_CPP20_CONSTEXPR
5931 : void
5932 : push_back (const_reference value)
5933 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5934 : requires CopyInsertable
5935 : #endif
5936 : {
5937 : emplace_back (value);
5938 : }
5939 :
5940 : PLUMED_GCH_CPP20_CONSTEXPR
5941 : void
5942 : push_back (value_type&& value)
5943 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5944 : requires MoveInsertable
5945 : #endif
5946 : {
5947 : emplace_back (std::move (value));
5948 142050 : }
5949 :
5950 : template <typename ...Args>
5951 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5952 : requires EmplaceConstructible<Args...>::value && MoveInsertable
5953 : #endif
5954 : PLUMED_GCH_CPP20_CONSTEXPR
5955 : reference
5956 : emplace_back (Args&&... args)
5957 : {
5958 2150913 : return *base::append_element (std::forward<Args> (args)...);
5959 : }
5960 :
5961 : PLUMED_GCH_CPP20_CONSTEXPR
5962 : void
5963 : pop_back (void)
5964 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5965 : requires Erasable
5966 : #endif
5967 : {
5968 : assert (! empty () && "`pop_back ()` called on an empty `small_vector`.");
5969 : base::erase_last ();
5970 137267 : }
5971 :
5972 : PLUMED_GCH_CPP20_CONSTEXPR
5973 : void
5974 : reserve (size_type new_capacity)
5975 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5976 : requires MoveInsertable
5977 : #endif
5978 : {
5979 50163 : base::request_capacity (new_capacity);
5980 50163 : }
5981 :
5982 : PLUMED_GCH_CPP20_CONSTEXPR
5983 : void
5984 : shrink_to_fit (void)
5985 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5986 : requires MoveInsertable
5987 : #endif
5988 : {
5989 : base::shrink_to_size ();
5990 : }
5991 :
5992 : PLUMED_GCH_CPP20_CONSTEXPR
5993 : void
5994 : clear (void) noexcept
5995 : #ifdef PLUMED_GCH_LIB_CONCEPTS
5996 : requires Erasable
5997 : #endif
5998 : {
5999 1509998 : base::erase_all ();
6000 : }
6001 :
6002 : PLUMED_GCH_CPP20_CONSTEXPR
6003 : void
6004 : resize (size_type count)
6005 : #ifdef PLUMED_GCH_LIB_CONCEPTS
6006 : requires MoveInsertable && DefaultInsertable
6007 : #endif
6008 : {
6009 : base::resize_with (count);
6010 : }
6011 :
6012 : PLUMED_GCH_CPP20_CONSTEXPR
6013 : void
6014 : resize (size_type count, const_reference value)
6015 : #ifdef PLUMED_GCH_LIB_CONCEPTS
6016 : requires CopyInsertable
6017 : #endif
6018 : {
6019 : base::resize_with (count, value);
6020 : }
6021 :
6022 : PLUMED_GCH_NODISCARD constexpr
6023 : bool
6024 : inlined (void) const noexcept
6025 : {
6026 : return ! base::has_allocation ();
6027 : }
6028 :
6029 : PLUMED_GCH_NODISCARD constexpr
6030 : bool
6031 : inlinable (void) const noexcept
6032 : {
6033 : return base::is_inlinable ();
6034 : }
6035 :
6036 : PLUMED_GCH_NODISCARD
6037 : static PLUMED_GCH_CONSTEVAL
6038 : size_type
6039 : inline_capacity (void) noexcept
6040 : {
6041 : return static_cast<size_type> (inline_capacity_v);
6042 : }
6043 :
6044 : #ifdef PLUMED_GCH_LIB_CONCEPTS
6045 : template <std::input_iterator InputIt>
6046 : requires EmplaceConstructible<std::iter_reference_t<InputIt>>::value
6047 : && MoveInsertable
6048 : #else
6049 : template <typename InputIt,
6050 : typename std::enable_if<std::is_base_of<
6051 : std::input_iterator_tag,
6052 : typename std::iterator_traits<InputIt>::iterator_category
6053 : >::value>::type * = nullptr>
6054 : #endif
6055 : PLUMED_GCH_CPP20_CONSTEXPR
6056 : small_vector&
6057 : append (InputIt first, InputIt last)
6058 : {
6059 : using policy = typename base::strong_exception_policy;
6060 : using iterator_cat = typename std::iterator_traits<InputIt>::iterator_category;
6061 : base::template append_range<policy> (first, last, iterator_cat { });
6062 : return *this;
6063 : }
6064 :
6065 : PLUMED_GCH_CPP20_CONSTEXPR
6066 : small_vector&
6067 : append (std::initializer_list<value_type> ilist)
6068 : #ifdef PLUMED_GCH_LIB_CONCEPTS
6069 : requires EmplaceConstructible<const_reference>::value
6070 : && MoveInsertable
6071 : #endif
6072 : {
6073 : return append (ilist.begin (), ilist.end ());
6074 : }
6075 :
6076 : template <unsigned I>
6077 : PLUMED_GCH_CPP20_CONSTEXPR
6078 : small_vector&
6079 : append (const small_vector<T, I, Allocator>& other)
6080 : #ifdef PLUMED_GCH_LIB_CONCEPTS
6081 : requires CopyInsertable
6082 : #endif
6083 : {
6084 : return append (other.begin (), other.end ());
6085 : }
6086 :
6087 : template <unsigned I>
6088 : PLUMED_GCH_CPP20_CONSTEXPR
6089 : small_vector&
6090 : append (small_vector<T, I, Allocator>&& other)
6091 : #ifdef PLUMED_GCH_LIB_CONCEPTS
6092 : requires MoveInsertable
6093 : #endif
6094 : {
6095 : // Provide a strong exception guarantee for `other` as well.
6096 : using move_iter_type = typename std::conditional<
6097 : base::template relocate_with_move<value_type>::value,
6098 : std::move_iterator<iterator>,
6099 : iterator>::type;
6100 :
6101 : append (move_iter_type { other.begin () }, move_iter_type { other.end () });
6102 : other.clear ();
6103 : return *this;
6104 : }
6105 : };
6106 :
6107 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6108 : inline PLUMED_GCH_CPP20_CONSTEXPR
6109 : bool
6110 : operator== (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6111 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6112 : {
6113 : return lhs.size () == rhs.size () && std::equal (lhs.begin (), lhs.end (), rhs.begin ());
6114 : }
6115 :
6116 : template <typename T, unsigned InlineCapacity, typename Allocator>
6117 : inline PLUMED_GCH_CPP20_CONSTEXPR
6118 : bool
6119 : operator== (const small_vector<T, InlineCapacity, Allocator>& lhs,
6120 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6121 : {
6122 : return lhs.size () == rhs.size () && std::equal (lhs.begin (), lhs.end (), rhs.begin ());
6123 : }
6124 :
6125 : #ifdef PLUMED_GCH_LIB_THREE_WAY_COMPARISON
6126 :
6127 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6128 : requires std::three_way_comparable<T>
6129 : constexpr
6130 : auto
6131 : operator<=> (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6132 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6133 : {
6134 : return std::lexicographical_compare_three_way (
6135 : lhs.begin (), lhs.end (),
6136 : rhs.begin (), rhs.end (),
6137 : std::compare_three_way { });
6138 : }
6139 :
6140 : template <typename T, unsigned InlineCapacity, typename Allocator>
6141 : requires std::three_way_comparable<T>
6142 : constexpr
6143 : auto
6144 : operator<=> (const small_vector<T, InlineCapacity, Allocator>& lhs,
6145 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6146 : {
6147 : return std::lexicographical_compare_three_way (
6148 : lhs.begin (), lhs.end (),
6149 : rhs.begin (), rhs.end (),
6150 : std::compare_three_way { });
6151 : }
6152 :
6153 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6154 : constexpr
6155 : auto
6156 : operator<=> (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6157 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6158 : {
6159 : constexpr auto comparison = [](const T& l, const T& r) {
6160 : return (l < r) ? std::weak_ordering::less
6161 : : (r < l) ? std::weak_ordering::greater
6162 : : std::weak_ordering::equivalent;
6163 : };
6164 :
6165 : return std::lexicographical_compare_three_way (
6166 : lhs.begin (), lhs.end (),
6167 : rhs.begin (), rhs.end (),
6168 : comparison);
6169 : }
6170 :
6171 : template <typename T, unsigned InlineCapacity, typename Allocator>
6172 : constexpr
6173 : auto
6174 : operator<=> (const small_vector<T, InlineCapacity, Allocator>& lhs,
6175 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6176 : {
6177 : constexpr auto comparison = [](const T& l, const T& r) {
6178 : return (l < r) ? std::weak_ordering::less
6179 : : (r < l) ? std::weak_ordering::greater
6180 : : std::weak_ordering::equivalent;
6181 : };
6182 :
6183 : return std::lexicographical_compare_three_way (
6184 : lhs.begin (), lhs.end (),
6185 : rhs.begin (), rhs.end (),
6186 : comparison);
6187 : }
6188 :
6189 : #else
6190 :
6191 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6192 : inline PLUMED_GCH_CPP20_CONSTEXPR
6193 : bool
6194 : operator!= (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6195 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6196 : {
6197 : return ! (lhs == rhs);
6198 : }
6199 :
6200 : template <typename T, unsigned InlineCapacity, typename Allocator>
6201 : inline PLUMED_GCH_CPP20_CONSTEXPR
6202 : bool
6203 : operator!= (const small_vector<T, InlineCapacity, Allocator>& lhs,
6204 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6205 : {
6206 : return ! (lhs == rhs);
6207 : }
6208 :
6209 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6210 : inline PLUMED_GCH_CPP20_CONSTEXPR
6211 : bool
6212 : operator< (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6213 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6214 : {
6215 : return std::lexicographical_compare (lhs.begin (), lhs.end (), rhs.begin (), rhs.end ());
6216 : }
6217 :
6218 : template <typename T, unsigned InlineCapacity, typename Allocator>
6219 : inline PLUMED_GCH_CPP20_CONSTEXPR
6220 : bool
6221 : operator< (const small_vector<T, InlineCapacity, Allocator>& lhs,
6222 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6223 : {
6224 : return std::lexicographical_compare (lhs.begin (), lhs.end (), rhs.begin (), rhs.end ());
6225 : }
6226 :
6227 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6228 : inline PLUMED_GCH_CPP20_CONSTEXPR
6229 : bool
6230 : operator>= (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6231 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6232 : {
6233 : return ! (lhs < rhs);
6234 : }
6235 :
6236 : template <typename T, unsigned InlineCapacity, typename Allocator>
6237 : inline PLUMED_GCH_CPP20_CONSTEXPR
6238 : bool
6239 : operator>= (const small_vector<T, InlineCapacity, Allocator>& lhs,
6240 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6241 : {
6242 : return ! (lhs < rhs);
6243 : }
6244 :
6245 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6246 : inline PLUMED_GCH_CPP20_CONSTEXPR
6247 : bool
6248 : operator> (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6249 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6250 : {
6251 : return rhs < lhs;
6252 : }
6253 :
6254 : template <typename T, unsigned InlineCapacity, typename Allocator>
6255 : inline PLUMED_GCH_CPP20_CONSTEXPR
6256 : bool
6257 : operator> (const small_vector<T, InlineCapacity, Allocator>& lhs,
6258 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6259 : {
6260 : return rhs < lhs;
6261 : }
6262 :
6263 : template <typename T, unsigned InlineCapacityLHS, unsigned InlineCapacityRHS, typename Allocator>
6264 : inline PLUMED_GCH_CPP20_CONSTEXPR
6265 : bool
6266 : operator<= (const small_vector<T, InlineCapacityLHS, Allocator>& lhs,
6267 : const small_vector<T, InlineCapacityRHS, Allocator>& rhs)
6268 : {
6269 : return rhs >= lhs;
6270 : }
6271 :
6272 : template <typename T, unsigned InlineCapacity, typename Allocator>
6273 : inline PLUMED_GCH_CPP20_CONSTEXPR
6274 : bool
6275 : operator<= (const small_vector<T, InlineCapacity, Allocator>& lhs,
6276 : const small_vector<T, InlineCapacity, Allocator>& rhs)
6277 : {
6278 : return rhs >= lhs;
6279 : }
6280 :
6281 : #endif
6282 :
6283 : template <typename T, unsigned InlineCapacity, typename Allocator
6284 : #ifndef PLUMED_GCH_LIB_CONCEPTS
6285 : , typename std::enable_if<std::is_move_constructible<T>::value
6286 : && std::is_move_assignable<T>::value
6287 : #ifdef PLUMED_GCH_LIB_IS_SWAPPABLE
6288 : && std::is_swappable<T>::value
6289 : #endif
6290 : >::type * = nullptr
6291 : #endif
6292 : >
6293 : inline PLUMED_GCH_CPP20_CONSTEXPR
6294 : void
6295 : swap (small_vector<T, InlineCapacity, Allocator>& lhs,
6296 : small_vector<T, InlineCapacity, Allocator>& rhs)
6297 : noexcept (noexcept (lhs.swap (rhs)))
6298 : #ifdef PLUMED_GCH_LIB_CONCEPTS
6299 : requires concepts::MoveInsertable<T, small_vector<T, InlineCapacity, Allocator>, Allocator>
6300 : && concepts::Swappable<T>
6301 : #endif
6302 : {
6303 : lhs.swap (rhs);
6304 : }
6305 :
6306 : template <typename T, unsigned InlineCapacity, typename Allocator, typename U>
6307 : inline PLUMED_GCH_CPP20_CONSTEXPR
6308 : typename small_vector<T, InlineCapacity, Allocator>::size_type
6309 : erase (small_vector<T, InlineCapacity, Allocator>& v, const U& value)
6310 : {
6311 : const auto original_size = v.size ();
6312 : v.erase (std::remove (v.begin (), v.end (), value), v.end ());
6313 : return original_size - v.size ();
6314 : }
6315 :
6316 : template <typename T, unsigned InlineCapacity, typename Allocator, typename Pred>
6317 : inline PLUMED_GCH_CPP20_CONSTEXPR
6318 : typename small_vector<T, InlineCapacity, Allocator>::size_type
6319 : erase_if (small_vector<T, InlineCapacity, Allocator>& v, Pred pred)
6320 : {
6321 : const auto original_size = v.size ();
6322 : v.erase (std::remove_if (v.begin (), v.end (), pred), v.end ());
6323 : return original_size - v.size ();
6324 : }
6325 :
6326 : template <typename T, unsigned InlineCapacity, typename Allocator>
6327 : constexpr
6328 : typename small_vector<T, InlineCapacity, Allocator>::iterator
6329 : begin (small_vector<T, InlineCapacity, Allocator>& v) noexcept
6330 : {
6331 : return v.begin ();
6332 : }
6333 :
6334 : template <typename T, unsigned InlineCapacity, typename Allocator>
6335 : constexpr
6336 : typename small_vector<T, InlineCapacity, Allocator>::const_iterator
6337 : begin (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6338 : {
6339 : return v.begin ();
6340 : }
6341 :
6342 : template <typename T, unsigned InlineCapacity, typename Allocator>
6343 : constexpr
6344 : typename small_vector<T, InlineCapacity, Allocator>::const_iterator
6345 : cbegin (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6346 : {
6347 : return begin (v);
6348 : }
6349 :
6350 : template <typename T, unsigned InlineCapacity, typename Allocator>
6351 : constexpr
6352 : typename small_vector<T, InlineCapacity, Allocator>::iterator
6353 : end (small_vector<T, InlineCapacity, Allocator>& v) noexcept
6354 : {
6355 : return v.end ();
6356 : }
6357 :
6358 : template <typename T, unsigned InlineCapacity, typename Allocator>
6359 : constexpr
6360 : typename small_vector<T, InlineCapacity, Allocator>::const_iterator
6361 : end (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6362 : {
6363 : return v.end ();
6364 : }
6365 :
6366 : template <typename T, unsigned InlineCapacity, typename Allocator>
6367 : constexpr
6368 : typename small_vector<T, InlineCapacity, Allocator>::const_iterator
6369 : cend (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6370 : {
6371 : return end (v);
6372 : }
6373 :
6374 : template <typename T, unsigned InlineCapacity, typename Allocator>
6375 : constexpr
6376 : typename small_vector<T, InlineCapacity, Allocator>::reverse_iterator
6377 : rbegin (small_vector<T, InlineCapacity, Allocator>& v) noexcept
6378 : {
6379 : return v.rbegin ();
6380 : }
6381 :
6382 : template <typename T, unsigned InlineCapacity, typename Allocator>
6383 : constexpr
6384 : typename small_vector<T, InlineCapacity, Allocator>::const_reverse_iterator
6385 : rbegin (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6386 : {
6387 : return v.rbegin ();
6388 : }
6389 :
6390 : template <typename T, unsigned InlineCapacity, typename Allocator>
6391 : constexpr
6392 : typename small_vector<T, InlineCapacity, Allocator>::const_reverse_iterator
6393 : crbegin (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6394 : {
6395 : return rbegin (v);
6396 : }
6397 :
6398 : template <typename T, unsigned InlineCapacity, typename Allocator>
6399 : constexpr
6400 : typename small_vector<T, InlineCapacity, Allocator>::reverse_iterator
6401 : rend (small_vector<T, InlineCapacity, Allocator>& v) noexcept
6402 : {
6403 : return v.rend ();
6404 : }
6405 :
6406 : template <typename T, unsigned InlineCapacity, typename Allocator>
6407 : constexpr
6408 : typename small_vector<T, InlineCapacity, Allocator>::const_reverse_iterator
6409 : rend (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6410 : {
6411 : return v.rend ();
6412 : }
6413 :
6414 : template <typename T, unsigned InlineCapacity, typename Allocator>
6415 : constexpr
6416 : typename small_vector<T, InlineCapacity, Allocator>::const_reverse_iterator
6417 : crend (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6418 : {
6419 : return rend (v);
6420 : }
6421 :
6422 : template <typename T, unsigned InlineCapacity, typename Allocator>
6423 : constexpr
6424 : typename small_vector<T, InlineCapacity, Allocator>::size_type
6425 : size (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6426 : {
6427 : return v.size ();
6428 : }
6429 :
6430 : template <typename T, unsigned InlineCapacity, typename Allocator>
6431 : constexpr
6432 : typename std::common_type<
6433 : std::ptrdiff_t,
6434 : typename std::make_signed<
6435 : typename small_vector<T, InlineCapacity, Allocator>::size_type>::type>::type
6436 : ssize (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6437 : {
6438 : using ret_type = typename std::common_type<
6439 : std::ptrdiff_t,
6440 : typename std::make_signed<decltype (v.size ())>::type>::type;
6441 : return static_cast<ret_type> (v.size ());
6442 : }
6443 :
6444 : template <typename T, unsigned InlineCapacity, typename Allocator>
6445 : PLUMED_GCH_NODISCARD constexpr
6446 : bool
6447 : empty (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6448 : {
6449 : return v.empty ();
6450 : }
6451 :
6452 : template <typename T, unsigned InlineCapacity, typename Allocator>
6453 : constexpr
6454 : typename small_vector<T, InlineCapacity, Allocator>::pointer
6455 : data (small_vector<T, InlineCapacity, Allocator>& v) noexcept
6456 : {
6457 : return v.data ();
6458 : }
6459 :
6460 : template <typename T, unsigned InlineCapacity, typename Allocator>
6461 : constexpr
6462 : typename small_vector<T, InlineCapacity, Allocator>::const_pointer
6463 : data (const small_vector<T, InlineCapacity, Allocator>& v) noexcept
6464 : {
6465 : return v.data ();
6466 : }
6467 :
6468 : #ifdef PLUMED_GCH_CTAD_SUPPORT
6469 :
6470 : template <typename InputIt,
6471 : unsigned InlineCapacity = default_buffer_size<
6472 : std::allocator<typename std::iterator_traits<InputIt>::value_type>>::value,
6473 : typename Allocator = std::allocator<typename std::iterator_traits<InputIt>::value_type>>
6474 : small_vector (InputIt, InputIt, Allocator = Allocator ())
6475 : -> small_vector<typename std::iterator_traits<InputIt>::value_type, InlineCapacity, Allocator>;
6476 :
6477 : #endif
6478 :
6479 : } // namespace gch
6480 : } // namespace PLMD
6481 :
6482 : #endif // PLUMED_GCH_SMALL_VECTOR_HPP
6483 : #endif
|