// SPDX-License-Identifier: LGPL-2.1+ #include "nm-default.h" #include "nm-std-utils.h" #include /*****************************************************************************/ size_t nm_utils_get_next_realloc_size (bool true_realloc, size_t requested) { size_t n, x; /* https://doc.qt.io/qt-5/containers.html#growth-strategies */ if (requested <= 40) { /* small allocations. Increase in small steps of 8 bytes. * * We get thus sizes of 8, 16, 32, 40. */ if (requested <= 8) return 8; if (requested <= 16) return 16; if (requested <= 32) return 32; /* The return values for < 104 are essentially hard-coded, and the choice here is * made without very strong reasons. * * We want to stay 24 bytes below the power-of-two border 64. Hence, return 40 here. * However, the next step then is already 104 (128 - 24). It's a larger gap than in * the steps before. * * It's not clear whether some of the steps should be adjusted (or how exactly). */ return 40; } if ( requested <= 0x2000u - 24u || NM_UNLIKELY (!true_realloc)) { /* mid sized allocations. Return next power of two, minus 24 bytes extra space * at the beginning. * That means, we double the size as we grow. * * With !true_realloc, it means that the caller does not intend to call * realloc() but instead clone the buffer. This is for example the case, when we * want to nm_explicit_bzero() the old buffer. In that case we really want to grow * the buffer exponentially every time and not increment in page sizes of 4K (below). * * We get thus sizes of 104, 232, 488, 1000, 2024, 4072, 8168... */ if (NM_UNLIKELY (requested > SIZE_MAX / 2u - 24u)) return SIZE_MAX; x = requested + 24u; n = 128u; while (n < x) { n <<= 1; nm_assert (n > 128u); } nm_assert (n > 24u && n - 24u >= requested); return n - 24u; } if (NM_UNLIKELY (requested > SIZE_MAX - 0x1000u - 24u)) return SIZE_MAX; /* For large allocations (with !true_realloc) we allocate memory in chunks of * 4K (- 24 bytes extra), assuming that the memory gets mmapped and thus * realloc() is efficient by just reordering pages. */ n = ((requested + (0x0FFFu + 24u)) & ~((size_t) 0x0FFFu)) - 24u; nm_assert (n >= requested); return n; }