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