From dceedcaa0b291821cee5bd39236edb07da5bfcc3 Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Thu, 15 Jan 2026 00:34:13 +0100 Subject: feat: make memory allocator configurable --- ls_vec.h | 119 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 33 deletions(-) diff --git a/ls_vec.h b/ls_vec.h index 5fcb454..7712873 100644 --- a/ls_vec.h +++ b/ls_vec.h @@ -5,56 +5,109 @@ #include #include -/* - * Lion's Standard (LS) ANSI C vector library. +/* Lion's Standard (LS) type-safe ANSI C vector. * - * This is a vector library, i.e. a dynamically sized array. - * To get started, you have to declare your type: + * Version: 1.0 + * Repo: https://github.com/lionkor/ls_vec + * SPDX-License-Identifier: MIT * - * VEC(int) + * ==== TABLE OF CONTENTS ==== * - * which creates a struct and the associated functions for a vec_int, - * meaning a vector of type `int`. The resulting struct is named `vec_int` - * and all associated functions are prefixed with that same name, for - * example `vec_int_init`, `vec_int_push`, etc. + * 1. DESCRIPTION + * 2. HOW TO USE + * 3. LICENSE * - * You can choose a name for long or complex types like this: + * ==== 1. DESCRIPTION ==== * - * VEC_NAMED(int*, intp) + * A minimal, terse, generic (macro code generated) header-only library in ANSI + * C, which implements a vector (dynamically sized array). * - * which results in vec_intp, vec_intp_push, etc. or + * The implementation uses standard malloc/realloc for memory management and + * automatically grows the capacity as needed. The memory allocator is + * configurable. * - * VEC_NAMED(struct Car, car) + * ==== 2. HOW TO USE ==== * - * which results in vec_car, vec_car_push, etc. + * Dynamically sized, type-safe vector. * - * The VEC and VEC_NAMED macros create both the declaration and implementation. - * If you'd like to split that, call + * Use LS_VEC_INLINE to generate a static inline version of the library. + * This is the "default" behavior. * - * VEC_DECL(int) + * If you need a declaration and implementation separately, use + * LS_VEC_DECL and make sure to call it with the same arguments as + * LS_VEC_IMPL. Put LS_VEC_DECL in a header, and LS_VEC_IMPL in exactly + * ONE source file. * - * to generate the declarations, and somewhere else + * Simple example: * - * VEC_IMPL(int) + * LS_VEC_INLINE(int, int_vector) * - * to generate the implementation. The same with VEC_NAMED_DECL - * and VEC_NAMED_IMPL. + * // somewhere in the same file + * int_vector vec; + * int_vector_init(&vec); + * int_vector_push(&vec, 42); + * // use vec.data, vec.size, etc. + * int_vector_clear(&vec); * - * Full example: + * Alternative example with decl and impl split: * - * VEC(int) + * // In your header file: + * LS_VEC_DECL(int, int_vector) * - * int main(void) { - * vec_int vec; - * vec_int_init(&vec); - * for (int i = 0; i < 10; ++i) { - * vec_int_push(&vec, i); - * } - * vec_int_clear(&vec); - * } + * // In one source file: + * LS_VEC_IMPL(int, int_vector) * + * // Usage in your code: + * int_vector vec; + * int_vector_init(&vec); + * if (!int_vector_push(&vec, 42)) { + * // handle allocation failure + * } + * // access elements via vec.data[i] + * int_vector_clear(&vec); + * + * You can configure a custom memory allocator by defining the macros LS_REALLOC + * and LS_FREE globally. These are the only allocation functions required, and + * they are expected to behave exactly as the standard requires. For example, + * LS_FREE(NULL) must be valid, LS_REALLOC can fail, LS_REALLOC with NULL will + * act like malloc, etc. + * + * ==== 3. LICENSE ==== + * + * This file is provided under the MIT license. For commercial support and + * maintenance, feel free to use the e-mail below to contact the author(s). + * + * The MIT License (MIT) + * + * Copyright (c) 2026 Lion Kortlepel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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 OR COPYRIGHT HOLDERS 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. */ +#ifndef LS_REALLOC +#define LS_REALLOC realloc +#endif + +#ifndef LS_FREE +#define LS_FREE free +#endif + #define LS_VEC_DECL(T, name) \ typedef struct name { \ size_t size; \ @@ -79,7 +132,7 @@ specifier void name##_init(name* vec) { memset(vec, 0, sizeof(*vec)); } \ specifier void name##_clear(name* vec) { \ if (vec->data) { \ - free(vec->data); \ + LS_FREE(vec->data); \ vec->data = NULL; \ } \ vec->size = 0; \ @@ -98,7 +151,7 @@ total = vec->capacity * sizeof(T); \ if (vec->capacity != 0 && total / vec->capacity != sizeof(T)) \ return 0; /* integer overflow */ \ - new_data = (T*)realloc(vec->data, total); \ + new_data = (T*)LS_REALLOC(vec->data, total); \ if (!new_data) \ return 0; \ vec->data = new_data; \ -- cgit