Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
ReserveTweaks.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <algorithm>
5
6#include "Stroika/Foundation/Math/Common.h"
7
8namespace Stroika::Foundation::Containers::Support::ReserveTweaks {
9
10 /*
11 ********************************************************************************
12 ****************************** GetScaledUpCapacity *****************************
13 ********************************************************************************
14 */
15 constexpr inline size_t GetScaledUpCapacity (size_t targetSize, [[maybe_unused]] size_t eltSizeInBytes, size_t minChunk)
16 {
17 Require (minChunk > 0u);
18 /*
19 * Rounding up works well at small scales - total memory
20 * waste is small (bounded). It is simple, and it helps speed up
21 * loops like while condition { append (); } considerably.
22 *
23 * Scaling up (multiplicatively) has the advantage that for large n, we get
24 * log(n) reallocs (rather than n/IncSize in the roundup case).
25 * This is much better long-term large-size performance.
26 * The only trouble with this approach is that in order to keep
27 * memory waste small, we must scale by a small number (here 20%)
28 * and so we need array sizes > 100 before we start seeing any real
29 * benefit at all. Such cases do happen, but we want to be able to
30 * optimize the much more common, small array cases too.
31 *
32 * So the compromise is to use a roundup-like strategy for
33 * small n, and a scaling approach as n gets larger.
34 */
35 size_t capacity{targetSize};
36 // if small, grow quicky
37 if (capacity <= 2 * minChunk) [[likely]] {
38 capacity *= 4;
39 }
40 else if (capacity <= 5 * minChunk) {
41 capacity *= 2;
42 }
43 else {
44 // if already large, then Grow by 20%
45 capacity = (capacity * 6) / 5;
46 }
47 // then adjust up to minimum chunk size
48 capacity = Math::RoundUpTo (capacity, minChunk);
49 Ensure (capacity >= targetSize);
50 return capacity;
51 }
52
53 /*
54 ********************************************************************************
55 ******************************* GetScaledUpCapacity4AddN ***********************
56 ********************************************************************************
57 */
58 template <typename CONTAINER>
59 constexpr inline optional<size_t> GetScaledUpCapacity4AddN (const CONTAINER& c, size_t addN, size_t minChunk)
60 {
61 size_t targetSize{c.size () + addN};
62 size_t capacity{c.capacity ()};
63 if (targetSize >= capacity) [[unlikely]] {
64 return GetScaledUpCapacity (targetSize, sizeof (typename CONTAINER::value_type), minChunk);
65 }
66 return nullopt;
67 }
68
69 /*
70 ********************************************************************************
71 ********************************** Reserve4AddN ********************************
72 ********************************************************************************
73 */
74 template <typename CONTAINER>
75 inline void Reserve4AddN (CONTAINER& c, size_t n, size_t minChunk)
76 {
77 if (auto newCapacity = GetScaledUpCapacity4AddN (c, n, minChunk)) [[unlikely]] {
78 c.reserve (*newCapacity);
79 }
80 }
81
82 /*
83 ********************************************************************************
84 ******************************* Reserve4Add1 ***********************************
85 ********************************************************************************
86 */
87 template <typename CONTAINER>
88 inline void Reserve4Add1 (CONTAINER& c, size_t minChunk)
89 {
90 Reserve4AddN (c, 1, minChunk);
91 }
92
93}