1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
/* TinyBuf - simple dynamic array - public domain - Bernhard Schelling 2020
https://github.com/schellingb/c-data-structures
no warranty implied; use at your own risk
This file implements stretchy buffers as invented (?) by Sean Barrett.
Based on the implementation from the public domain Bitwise project
by Per Vognsen - https://github.com/pervognsen/bitwise
It's a super simple type safe dynamic array for C with no need
to predeclare any type or anything.
The first time an element is added, memory for 16 elements are allocated.
Then every time length is about to exceed capacity, capacity is doubled.
Can be used in C++ with POD types (without any constructor/destructor).
Be careful not to supply modifying statements to the macro arguments.
Something like BUF_REMOVE(buf, i--); would have unintended results.
--- Added by Pierre Gentile - p.gen.progs@gmail.com - 2024 ---
BUF_MALLOC and BUF_REALLOC can be #defined to specify alternative memory
allocation and reallocation functions.
When not #defined, the standard malloc and realloc functions are used.
--- End ---
Sample usage:
mytype_t* buf = NULL;
BUF_PUSH(buf, some_element);
BUF_PUSH(buf, other_element);
-- now BUF_LEN(buf) == 2, buf[0] == some_element, buf[1] == other_element
-- Free allocated memory:
BUF_FREE(buf);
-- now buf == NULL, BUF_LEN(buf) == 0, BUF_CAP(buf) == 0
-- Explicitly increase allocated memory and set capacity:
BUF_FIT(buf, 100);
-- now BUF_LEN(buf) == 0, BUF_CAP(buf) == 100
-- Resize buffer (does not initialize or zero memory!):
BUF_RESIZE(buf, 200);
-- now BUF_LEN(buf) == 200, BUF_CAP(buf) == 200
-- Remove an element in the middle, keeping order:
BUF_REMOVE(buf, 30);
-- now BUF_LEN(buf) == 199, everything past 30 shifted 1 up
-- Remove an element in the middle, swapping the last element into it:
BUF_SWAPREMOVE(buf, 10);
-- now BUF_LEN(buf) == 198, element 198 was copied into 10
-- Insert an element into the middle of the array:
BUF_INSERT(buf, 100, some_element);
-- now BUF_LEN(buf) == 199, everything past 99 shifted 1 down
-- Make a gap of a given size in the middle of the array:
mytype_t* ptr_gap = BUF_MAKEGAP(buf, 20, 11);
-- now BUF_LEN(buf) == 210, everything past 19 shifted 11 down
-- Add multiple elements at the end (uninitialized):
mytype_t* ptr1 = BUF_ADD(buf, 10);
-- now BUF_LEN(buf) == 220, ptr1 points to buf[210]
-- Add multiple elements at the end (zeroing memory):
mytype_t* ptr2 = BUF_ADDZEROED(buf, 10);
-- now BUF_LEN(buf) == 230, ptr2 points to buf[220]
-- To handle running out of memory:
bool ran_out_of_memory = !BUF_TRYFIT(buf, 1000);
-- before RESIZE or PUSH. When out of memory, buf will stay unmodified.
PUBLIC DOMAIN (UNLICENSE)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
#ifndef TINYBUF_H
#define TINYBUF_H
#include <stdlib.h> /* for malloc, realloc */
#include <string.h> /* for memmove, memset */
#include <stddef.h> /* for size_t */
/* Query functions. */
/* """""""""""""""" */
#define BUF_LEN(b) ((b) ? BUF__HDR(b)->len : 0)
#define BUF_CAP(b) ((b) ? BUF__HDR(b)->cap : 0)
#define BUF_END(b) ((b) + BUF_LEN(b))
#define BUF_SIZEOF(b) ((b) ? BUF_LEN(b) * sizeof(*b) : 0)
/* Modifying functions. */
/* """""""""""""""""""" */
#define BUF_FREE(b) \
((b) ? (free(BUF__HDR(b)), (*(void **)(&(b)) = (void *)0)) : 0)
#define BUF_FIT(b, n) \
((size_t)(n) <= BUF_CAP(b) \
? 0 \
: (*(void **)(&(b)) = buf__grow((b), (size_t)(n), sizeof(*(b)))))
#define BUF_PUSH(b, val) \
(BUF_FIT((b), BUF_LEN(b) + 1), (b)[BUF__HDR(b)->len++] = (val))
#define BUF_POP(b) (b)[--BUF__HDR(b)->len]
#define BUF_RESIZE(b, sz) \
(BUF_FIT((b), (sz)), ((b) ? BUF__HDR(b)->len = (sz) : 0))
#define BUF_CLEAR(b) ((b) ? BUF__HDR(b)->len = 0 : 0)
#define BUF_TRYFIT(b, n) \
(BUF_FIT((b), (n)), (((b) && BUF_CAP(b) >= (size_t)(n)) || !(n)))
/* Utility functions. */
/* """""""""""""""""" */
#define BUF_SHIFT(b, to, fr, n) \
((b) ? memmove((b) + (to), (b) + (fr), (n) * sizeof(*(b))) : 0)
#define BUF_REMOVE(b, idx) \
(BUF_SHIFT(b, idx, (idx) + 1, --BUF__HDR(b)->len - (idx)))
#define BUF_SWAPREMOVE(b, idx) (BUF_SHIFT(b, idx, --BUF__HDR(b)->len, 1))
#define BUF_MAKEGAP(b, idx, sz) \
(BUF_RESIZE((b), BUF_LEN(b) + (sz)), \
BUF_SHIFT(b, (idx) + (sz), idx, BUF_LEN(b) - (idx) - (sz)), \
(b) + (idx))
#define BUF_INSERT(b, idx, val) (*BUF_MAKEGAP(b, idx, 1) = (val))
#define BUF_ZERO(b, idx, n) (memset((b) + (idx), 0, (n) * sizeof(*(b))))
#define BUF_ADD(b, n) \
(BUF_FIT(b, BUF_LEN(b) + (n)), (b) + (BUF__HDR(b)->len += (n)) - (n))
#define BUF_ADDZEROED(b, n) \
(BUF_FIT(b, BUF_LEN(b) + (n)), \
BUF_ZERO(b, BUF_LEN(b), n), \
(b) + (BUF__HDR(b)->len += (n)) - (n))
#define BUF__HDR(b) (((struct buf__hdr *)(b)) - 1)
struct buf__hdr
{
size_t len, cap;
};
#ifdef __GNUC__
__attribute__((__unused__))
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4505) /* Unref. local function has been removed. */
#endif
#ifndef BUF_MALLOC
#define BUF_MALLOC malloc
#endif
#ifndef BUF_REALLOC
#define BUF_REALLOC realloc
#endif
static void *
buf__grow(void *buf, size_t new_len, size_t elem_size)
{
struct buf__hdr *new_hdr;
size_t new_cap = 2 * BUF_CAP(buf), new_size;
if (new_cap < new_len)
new_cap = new_len;
if (new_cap < 16)
new_cap = 16;
new_size = sizeof(struct buf__hdr) + new_cap * elem_size;
if (buf)
{
new_hdr = (struct buf__hdr *)BUF_REALLOC(BUF__HDR(buf), new_size);
if (!new_hdr)
return buf; /* Out of memory, return unchanged. */
}
else
{
new_hdr = (struct buf__hdr *)BUF_MALLOC(new_size);
if (!new_hdr)
return (void *)0; /* Out of memory. */
new_hdr->len = 0;
}
new_hdr->cap = new_cap;
return new_hdr + 1;
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#endif
|