summary refs log tree commit diff
path: root/shared/nm-std-aux/nm-std-utils.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-10-05 22:27:18 +0200
committerMichael Biebl <biebl@debian.org>2020-10-05 22:27:18 +0200
commitaafc1dbe4712c86189bbc1d4d54ad8cb4c69be7e (patch)
treea2a9bb4d007339a0b1304540388230ccedac32bd /shared/nm-std-aux/nm-std-utils.c
parente7b44ef4c80907346ec7492a09c45277459924fc (diff)
New upstream version 1.27.90 upstream/1.27.90
Diffstat (limited to 'shared/nm-std-aux/nm-std-utils.c')
-rw-r--r--shared/nm-std-aux/nm-std-utils.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/shared/nm-std-aux/nm-std-utils.c b/shared/nm-std-aux/nm-std-utils.c
new file mode 100644
index 00000000..6f7f4c58
--- /dev/null
+++ b/shared/nm-std-aux/nm-std-utils.c
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "nm-default.h"
+
+#include "nm-std-utils.h"
+
+#include <stdint.h>
+
+/*****************************************************************************/
+
+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;
+}