/* Lion's Standard (LS) type-safe ANSI C vector.
*
* Version: 2.0
* Website: https://libls.org
* GitHub: https://github.com/libls/vec
* Mirror: https://git.libls.org/vec.git
* SPDX-License-Identifier: MIT
*
* ==== TABLE OF CONTENTS ====
*
* 1. DESCRIPTION
* 2. HOW TO USE
* 3. LICENSE
*
* ==== 1. DESCRIPTION ====
*
* A minimal, terse, generic (macro code generated) header-only library in ANSI
* C, which implements a vector (dynamically sized array).
*
* The implementation uses standard malloc/realloc for memory management and
* automatically grows the capacity as needed. The memory allocator is
* configurable.
*
* ==== 2. HOW TO USE ====
*
* Dynamically sized, type-safe vector.
*
* Use LS_VEC_INLINE to generate a static inline version of the library.
* This is the "default" behavior.
*
* 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.
*
* Simple example:
*
* LS_VEC_INLINE(int, int_vector)
*
* // 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_free(&vec);
*
* Alternative example with decl and impl split:
*
* // In your header file:
* LS_VEC_DECL(int, int_vector)
*
* // 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_free(&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 <[email protected]>
*
* 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.
*/
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#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; \
size_t capacity; \
T* data; \
} name; \
void name##_init(name* vec); \
void name##_free(name* vec); \
int name##_reserve(name* vec, size_t count); \
int name##_push(name* vec, T value);
#define LS_VEC_IMPL(T, name) _ls_VEC_IMPL_DETAIL(T, name, )
#define LS_VEC_INLINE(T, name) \
typedef struct name { \
size_t size; \
size_t capacity; \
T* data; \
} name; \
_ls_VEC_IMPL_DETAIL(T, name, static)
#define _ls_VEC_IMPL_DETAIL(T, name, specifier) \
specifier void name##_init(name* vec) { memset(vec, 0, sizeof(*vec)); } \
specifier void name##_free(name* vec) { \
if (vec->data) { \
LS_FREE(vec->data); \
vec->data = NULL; \
} \
vec->size = 0; \
vec->capacity = 0; \
} \
specifier int name##_reserve(name* vec, size_t count) { \
if (vec->capacity < count) { \
T* new_data; \
size_t max_items = SIZE_MAX / sizeof(T); \
size_t new_cap = vec->capacity + vec->capacity / 2 + 8; \
if (new_cap < count) { \
new_cap = count; \
} \
/* overflow check */ \
if (new_cap > max_items) { \
return 0; \
} \
new_data = (T*)LS_REALLOC(vec->data, new_cap * sizeof(T)); \
if (new_data == NULL) { \
return 0; \
} \
vec->capacity = new_cap; \
vec->data = new_data; \
} \
return 1; \
} \
specifier int name##_push(name* vec, T value) { \
if (!name##_reserve(vec, vec->size + 1)) { \
return 0; \
} \
vec->data[vec->size++] = value; \
return 1; \
} \
specifier int name##_pop(name* vec, T* out_value) { \
if (vec->size == 0) { \
return 0; \
} \
*out_value = vec->data[--vec->size]; \
return 1; \
}