From: Mark Wooding Date: Mon, 15 Jul 2024 22:32:04 +0000 (+0100) Subject: @@@ random mess X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/commitdiff_plain/d93e9a33ee30faed3945b2a7acfc46b84197d432?ds=sidebyside @@@ random mess --- diff --git a/mem/alloc.c b/mem/alloc.c index 8a62617..3f1ccc5 100644 --- a/mem/alloc.c +++ b/mem/alloc.c @@ -41,7 +41,7 @@ /*----- Functions and macros ----------------------------------------------*/ -/* --- @x_alloc@, @x_allocn@ --- * +/* --- @x_alloc@, @x_allocv@ --- * * * Arguments: @arena *a@ = pointer to underlying arena * @size_t n@ = number of elements to allocate (for @x_allocv@) @@ -49,7 +49,7 @@ * * Returns: Pointer to allocated block. * - * Use: The @x_allocn@ function allocates memory for @n@ elements of + * Use: The @x_allocv@ function allocates memory for @n@ elements of * @sz@ bytes each (or, perhaps, %%\emph{vice versa}). The * @x_alloc@ function is the same, but with @n@ fixed equal * to 1. If there's not enough memory, the exception diff --git a/mem/alloc.h b/mem/alloc.h index 8a5c364..eb70dc0 100644 --- a/mem/alloc.h +++ b/mem/alloc.h @@ -64,12 +64,16 @@ extern void *x_allocv(arena */*a*/, size_t /*n*/, size_t /*sz*/); * * Arguments: @type *p@ = a pointer to allocate * @arena *a@ = pointer to underlying arena - * @size_t n@ = number of elements + * @size_t n@ = number of elements (for @X_NEWV@) * * Returns: --- * - * Use: Set @p@ to point to a freshly allocate block large enough for - * @n@ elements each of the type pointed to by @p@. + * Use: The @X_NEW@ macro sets @p@ to point to a freshly allocated + * block of memory large enough for an object of the type + * pointed to by @p@. The @X_NEWV@ macro allocated enough space + * for a vector of @n@ elements, each of the type pointed to by + * @p@. If there is not enough memory, the exception + * @EXC_NOMEM@ is thrown. */ #define X_NEW(p, a) do { (p) = x_alloc((a), sizeof(*(p))); } while (0) @@ -108,10 +112,10 @@ extern char *x_strdup(arena */*a*/, const char */*s*/); * * The @x_reallocv@ function adjusts a block which currently has * space for @on@ elements each of size @sz@, so that it now has - * enough space for @n@ elements, preserving the initial @min(n, - * on)@ elements. The @x_realloc@ function is the same, but - * with @sz@ fixed equal to 1, and @n@ and @on@ renamed to @sz@ - * and @osz@ for historical reasons. + * enough space for @n@ elements, preserving the initial + * @min(n, on)@ elements. The @x_realloc@ function is the same, + * but with @sz@ fixed equal to 1, and @n@ and @on@ renamed to + * @sz@ and @osz@ for historical reasons. */ extern void *x_realloc(arena */*a*/, void */*p*/, diff --git a/mem/arena.h b/mem/arena.h index fad4fa9..e4585f7 100644 --- a/mem/arena.h +++ b/mem/arena.h @@ -56,7 +56,7 @@ typedef struct arena_ops { extern arena *arena_global; /* Standard global arena */ extern arena arena_stdlib; /* Arena based on @malloc@/@free@ */ -/*----- Functions provided ------------------------------------------------*/ +/*----- Allocation utilities ----------------------------------------------*/ /* --- @ALLOCV_SAFE_P@, @NEWV_SAFE_P@ --- * @@ -72,6 +72,8 @@ extern arena arena_stdlib; /* Arena based on @malloc@/@free@ */ #define ALLOCV_SAFE_P(n, sz) ((n) <= (size_t)-1/(sz)) #define NEWV_SAFE_P(p, n) (ALLOCV_SAFE_P((n), sizeof(*(p)))) +/*----- Arena implementation utilities ------------------------------------*/ + /* --- @arena_fakerealloc@ --- * * * Arguments: @arena *a@ = pointer to arena block @@ -88,35 +90,119 @@ extern arena arena_stdlib; /* Arena based on @malloc@/@free@ */ extern void *arena_fakerealloc(arena */*a*/, void */*p*/, size_t /*sz*/, size_t /*osz*/); -/* --- Useful macros --- */ +/* --- @a_alloc@, @A_ALLOC@, @a_allocv@, @A_ALLOCV@ --- * + * + * Arguments: @arena *a@ = pointer to arena + * @size_t n@ = number of element (for @a_allocv@, @A_ALLOCV@) + * @size_t sz@ = size to each element + * + * Returns: Pointer to the newly allocated block, or null on failure. + * + * Use: Allocate and return a block from the arena @a@ large enough + * for a vector of @n@ elements each @sz@ bytes in size. If + * sufficient storage is not available, return a null pointer. + * (Some arenas may choose to abort the program instead.) + */ + +extern void *a_alloc(arena */*a*/, size_t /*sz*/); +extern void *a_allocv(arena */*a*/, size_t /*n*/, size_t /*sz*/); #define A_ALLOC(a, sz) (((a)->ops->alloc)((a), (sz))) #define A_ALLOCV(a, n, sz) \ (ALLOCV_SAFE_P((n), (sz)) ? ((a)->ops->alloc)((a), (n)*(sz)) : 0) + +/* --- @A_NEW@, @A_NEWV@ --- * + * + * Arguments: @type *p@ = pointer to object type + * @arena *a@ = pointer to arena + * @size_t n@ = number of elements to allocate (for @A_NEWV@) + * + * Returns: --- + * + * Use: Set @p@ to point to a freshly allocated block of memory large + * enough for @n@ elements of the type that it points to, or a + * null pointer. + * + */ + #define A_NEW(p, a) do { (p) = A_ALLOC((a), sizeof(*(p))); } while (0) #define A_NEWV(p, a, n) \ do { (p) = A_ALLOCV((a), (n), sizeof(*(p))); } while (0) + +/* --- @a_realloc, @A_REALLOC@, @a_reallocv@, @A_REALLOCV@ --- * + * + * Arguments: @arena *a@ = pointer to arena + * @void *p@ = pointer to existing block + * @size_t n@ = new number of elements (for @a_reallocv@, + * @A_REALLOCV@) + * @size_t on@ = old number of elements (for @a_reallocv@, + * @A_REALLOCV@) + * @size_t sz@ = size of elements (for @a_reallocv@, + * @A_REALLOCV@) or new block size (@a_realloc@, + * @A_REALLOC@) + * @size_t osz@ = old block size (@a_realloc@, @A_REALLOC@) + * + * Returns: Pointer to the new block, or null on failure. + * + * Use: The @a_reallocv@ function and @A_REALLOCV@ macro adjust a + * block which currently has space for @on@ elements each of + * size @sz@, so that it now has enough space for @n@ elements, + * preserving the initial @min(n, on)@ elements. The + * @a_realloc@ function and @A_REALLOC@ macro are the same, but + * with @sz@ fixed equal to 1, and @n@ and @on@ renamed to @sz@ + * and @osz@ for historical reasons. + */ + +extern void *a_realloc(arena */*a*/, void */*p*/, + size_t /*sz*/, size_t /*osz*/); +extern void *a_reallocv(arena */*a*/, void */*p*/, + size_t /*n*/, size_t /*on*/, size_t /*sz*/); + #define A_REALLOC(a, p, sz, osz) \ (((a)->ops->realloc)((a), (p), (sz), (osz))) #define A_REALLOCV(a, p, n, on, sz) \ (ALLOCV_SAFE_P((n), (sz)) ? \ ((a)->ops->realloc)((a), (p), (n)*(sz), (on)*(sz)) : 0) + +/* --- @A_RENEWV@ --- * + * + * Arguments: @type *q@ = pointer to set + * @type *p@ = pointer to existing allocation + * @arena *a@ = pointer to arena + * @size_t n@ = number of elements to allocate + * + * Returns: --- + * + * Use: On entry, @p@ should point to a block of memory allocated + * from @a@, with enough space for @on@ elements of the type + * pointed to by @p@ and @q@. The macro attempts to adjusts + * this block so that it has enough space for @n@ elements, + * preserving the initial @min(n, on)@ elements, and stores a + * pointer to the block's new address in @q@ if successful; on + * failure, @q@ is set to a null pointer and the block remains + * unchanged. + * + */ + #define A_RENEWV(q, p, a, n, on) do { \ (q) = !sizeof((*(p)) = (*(q))) + \ A_REALLOCV((a), (p), (n), (on), sizeof(*(p))); \ } while (0) -#define A_FREE(a, p) (((a)->ops->free)((a), (p))) -/* --- Simple function equivalents --- */ +/* --- @a_free@, @A_FREE@ --- * + * + * Arguments: @arena *a@ = pointer to arena + * @void *p@ = pointer to existing block + * + * Returns: --- + * + * Use: Release the block pointed to by @p@. + */ -extern void *a_alloc(arena */*a*/, size_t /*sz*/); -extern void *a_allocv(arena */*a*/, size_t /*n*/, size_t /*sz*/); -extern void *a_realloc(arena */*a*/, void */*p*/, - size_t /*sz*/, size_t /*osz*/); -extern void *a_reallocv(arena */*a*/, void */*p*/, - size_t /*n*/, size_t /*on*/, size_t /*sz*/); extern void a_free(arena */*a*/, void */*p*/); +#define A_FREE(a, p) (((a)->ops->free)((a), (p))) + /*----- That's all, folks -------------------------------------------------*/ #ifdef __cplusplus diff --git a/utils/macros.h b/utils/macros.h index 2ca5a06..b48e6f6 100644 --- a/utils/macros.h +++ b/utils/macros.h @@ -92,7 +92,7 @@ IGNORABLE extern char static_assert_failed[1 - 2*!(cond)] #endif -/* --- @CHECK_TYPE@ --- +/* --- @CHECK_TYPE@ --- * * * Arguments: @expty@ = expected type of @x@ * @expty x@ = some object @@ -105,7 +105,7 @@ #define CHECK_TYPE(expty, x) (!sizeof(*(expty *)0 = (x))) -/* --- @CONVERT_CAREFULLY@ --- +/* --- @CONVERT_CAREFULLY@ --- * * * Arguments: @newty@ = new type for the result * @expty@ = expected type of @x@ @@ -121,6 +121,19 @@ #define CONVERT_CAREFULLY(newty, expty, x) \ (CHECK_TYPE(expty, x) + (/*unconst unvolatile*/ newty)(x)) +/* --- @CONTAINER@ --- * + * + * Arguments: @type@ = the parent type, a structure or union + * @mem@ = the name of the member we have a pointer to + * @memty *p@ = pointer to @member@ within @type@ + * + * Returns: The address of the containing @ty@ object. + */ + +#define CONTAINER(type, member, p) \ + (!sizeof((p) = &((type *)0)->mem) + \ + (type *)((unsigned char *)(p) - offsetof(type, mem))) + /* --- @UNCONST@, @UNVOLATILE@, @UNQUALIFY@ --- * * * Arguments: @type@ = a type name