Skip to content

Instantly share code, notes, and snippets.

@haseeb-heaven
Last active November 1, 2025 08:23
Show Gist options
  • Select an option

  • Save haseeb-heaven/fe7c9ac61f0852d0f6ee38b7c28bbf26 to your computer and use it in GitHub Desktop.

Select an option

Save haseeb-heaven/fe7c9ac61f0852d0f6ee38b7c28bbf26 to your computer and use it in GitHub Desktop.
A simple and safe dynamic array in C that grows automatically, checks index bounds, prevents crashes from invalid access, and makes handling lists of data easier and safer.
/**
* stb_vector.h - v1.0 - public domain type-safe generic dynamic arrays
*
* This is a single-header-file library that provides easy-to-use
* dynamic arrays for C (also works in C++).
*
* DO THIS ONCE, AT THE START OF ONE SOURCE FILE:
* #define STB_VECTOR_IMPLEMENTATION
* #include "stb_vector.h"
*
* OTHER FILES:
* #include "stb_vector.h"
*
* QUICK EXAMPLE:
* ──────────────
*
* #define STB_VECTOR_IMPLEMENTATION
* #include "stb_vector.h"
* #include <stdio.h>
*
* int main(void) {
* Vector(int) *vec = vector_new(int);
*
* $(vec)->resize(2); // Allocate space for 2 elements
* $(vec)->set(0, 10);
* $(vec)->set(1, 20);
* $(vec)->push_back(30);
*
* printf("Initial: ");
* for (size_t index = 0; index < $(vec)->size(); ++index)
* printf("%d ", $(vec)->get(index));
* printf("\n");
*
* $(vec)->erase(1); // Remove element at index 1
*
* printf("Size: %zu, Capacity: %zu\n", $(vec)->size(), $(vec)->capacity());
*
* printf("Remaining: ");
* for (size_t index = 0; index < $(vec)->size(); ++index)
* printf("%d ", $(vec)->get(index));
* printf("\n");
*
* $(vec)->destroy();
* return 0;
* }
*
* API REFERENCE:
* ──────────────
*
* CREATION:
* Vector(T) *vec = vector_new(T); // empty
* Vector(T) *vec = vector_new(T, 10); // sized
* Vector(T) *vec = vector_new(T, 10, value); // filled
*
* MODIFICATION:
* $(vec)->push_back(value); // O(1) amortized
* $(vec)->pop_back(); // O(1)
* $(vec)->insert(idx, value); // O(n)
* $(vec)->erase(idx); // O(n)
* $(vec)->set(idx, value); // O(1)
* $(vec)->resize(new_size); // O(n) if growing
* $(vec)->reserve(capacity); // O(n) if growing
* $(vec)->clear(); // O(1)
*
* ACCESS (WITH BOUNDS CHECKING):
* T value = $(vec)->get(idx); // read element
* T value = $(vec)->front(); // first element
* T value = $(vec)->back(); // last element
* T *ptr = $(vec)->data_ptr(); // raw pointer
*
* INFORMATION:
* size_t len = $(vec)->size(); // current size
* size_t cap = $(vec)->capacity(); // allocated capacity
* int empty = $(vec)->empty(); // check if empty
*
* OPTIMIZATION:
* $(vec)->shrink_to_fit(); // release unused memory
* $(vec)->swap(other_vec); // O(1) swap
*
* CLEANUP:
* $(vec)->destroy(); // free internal data
* free(vec); // free struct
*
* EXCEPTION HANDLING:
* stb_try(vec) {
* $(vec)->push_back(10);
* $(vec)->get(999); // Throws exception!
* } stb_catch {
* printf("Error: %s\n", vec->error.message);
* }
*
* SUPPORTED TYPES:
* Built-in: int, float, double, char, long
* Custom: DECLARE_VECTOR(your_type)
*
* THREAD SAFETY:
* ✓ Thread-local error contexts
* ✓ Safe for different instances in different threads
* ✗ NOT safe to share same vector across threads
*
* MEMORY SAFETY:
* ✓ Bounds checking on all operations
* ✓ Magic number validation (use-after-free detection)
* ✓ Allocation failure handling
* ✓ Detailed error messages
*
* TIME COMPLEXITY:
* push_back: O(1) amortized pop_back: O(1)
* get/set: O(1) insert: O(n)
* erase: O(n) resize: O(n)
* clear: O(1)
*
* PERFORMANCE:
* • Exponential growth (2x doubling) for amortized O(1) push
* • Minimal overhead: ~40 bytes per vector struct
* • Zero external dependencies
* • Optimized for cache locality
*
* LIMITATIONS:
* • Not suitable for strict real-time (setjmp/longjmp overhead)
* • Element access requires context binding macro: $(vec)
* • Maximum element size: SIZE_MAX / sizeof(T)
*
* PORTABILITY:
* ✓ C89/C90 and later
* ✓ MSVC, GCC, Clang
* ✓ Windows, Linux, macOS, Unix
* ✓ 32-bit and 64-bit systems
* ✓ C++ compatible all the way to C++17
*
* LICENSE
* ═══════════════════════════════════════════════════════════════════════════
*
* This software is available under 2 licenses -- choose whichever you prefer.
*
* ALTERNATIVE A - MIT License
* Copyright (c) 2025 Haseeb Mir
*
* 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.
*
* ALTERNATIVE B - Public Domain
* 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.
*
* ═══════════════════════════════════════════════════════════════════════════
*/
#ifndef STB_VECTOR_H
#define STB_VECTOR_H
#include <stddef.h>
#include <setjmp.h>
#include <limits.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ════════════════════════════════════════════════════════════════════════════
* CONFIGURATION
* ════════════════════════════════════════════════════════════════════════════ */
#ifndef STB_VECTOR_MALLOC
#define STB_VECTOR_MALLOC(sz, ctx) malloc(sz)
#endif
#ifndef STB_VECTOR_REALLOC
#define STB_VECTOR_REALLOC(ptr, sz, ctx) realloc(ptr, sz)
#endif
#ifndef STB_VECTOR_FREE
#define STB_VECTOR_FREE(ptr, ctx) free(ptr)
#endif
#define STB_VECTOR_MAGIC 0xDEADBEEF
#define STB_VECTOR_MAX_SIZE(T) (SIZE_MAX / sizeof(T))
#define STB_VECTOR_INITIAL_CAPACITY 1
#define STB_VECTOR_GROWTH_FACTOR 2
/* ════════════════════════════════════════════════════════════════════════════
* ERROR CODES & STRUCTURES
* ════════════════════════════════════════════════════════════════════════════ */
typedef enum {
STB_VEC_ERR_NONE = 0,
STB_VEC_ERR_OUT_OF_BOUNDS = 1,
STB_VEC_ERR_ALLOCATION_FAILED = 2,
STB_VEC_ERR_LENGTH_ERROR = 3,
STB_VEC_ERR_INVALID_VECTOR = 4
} STB_VectorErrorCode;
typedef struct {
jmp_buf env;
STB_VectorErrorCode code;
char message[256];
int active;
} STB_VectorErrorHandler;
/* ════════════════════════════════════════════════════════════════════════════
* PUBLIC DECLARATIONS (always included)
* ════════════════════════════════════════════════════════════════════════════ */
/* Forward declarations */
typedef struct STB_Vector_int STB_Vector_int;
typedef struct STB_Vector_float STB_Vector_float;
typedef struct STB_Vector_double STB_Vector_double;
typedef struct STB_Vector_char STB_Vector_char;
typedef struct STB_Vector_long STB_Vector_long;
/* Thread-local contexts */
extern __thread void *_stb_vec_ctx_current;
extern __thread STB_Vector_int *_stb_vec_ctx_int;
extern __thread STB_Vector_float *_stb_vec_ctx_float;
extern __thread STB_Vector_double *_stb_vec_ctx_double;
extern __thread STB_Vector_char *_stb_vec_ctx_char;
extern __thread STB_Vector_long *_stb_vec_ctx_long;
/* Public API Macros */
#define Vector(T) STB_Vector_##T
#define _STB_VEC_SELECT(_1, _2, _3, NAME, ...) NAME
#define vector_new(...) _STB_VEC_SELECT(__VA_ARGS__, _stb_vec_create_fill, _stb_vec_create_size, _stb_vec_create)(__VA_ARGS__)
#define _stb_vec_create(T) _stb_vec_create_##T(0, NULL)
#define _stb_vec_create_size(T, n) _stb_vec_create_size_##T(n, NULL)
#define _stb_vec_create_fill(T, n, fill) _stb_vec_create_fill_##T(n, fill, NULL)
#define $(vec) (_stb_vec_ctx_current = (vec), (vec))
#define stb_try(vec) if (setjmp((vec)->error.env) == STB_VEC_ERR_NONE)
#define stb_catch else
#define RAISE(vec, msg) do { \
if (!(vec)) break; \
strncpy((vec)->error.message, (msg), sizeof((vec)->error.message) - 1); \
(vec)->error.message[sizeof((vec)->error.message) - 1] = '\0'; \
longjmp((vec)->error.env, STB_VEC_ERR_INVALID_VECTOR); \
} while (0)
#endif /* STB_VECTOR_H */
/* ════════════════════════════════════════════════════════════════════════════
* IMPLEMENTATION (only if STB_VECTOR_IMPLEMENTATION is defined)
* ════════════════════════════════════════════════════════════════════════════ */
#ifdef STB_VECTOR_IMPLEMENTATION
#undef STB_VECTOR_IMPLEMENTATION
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* Thread-local storage (implementation) */
__thread void *_stb_vec_ctx_current = NULL;
__thread STB_Vector_int *_stb_vec_ctx_int = NULL;
__thread STB_Vector_float *_stb_vec_ctx_float = NULL;
__thread STB_Vector_double *_stb_vec_ctx_double = NULL;
__thread STB_Vector_char *_stb_vec_ctx_char = NULL;
__thread STB_Vector_long *_stb_vec_ctx_long = NULL;
/* ════════════════════════════════════════════════════════════════════════════
* UNIVERSAL MACRO FOR TYPE GENERATION
* ════════════════════════════════════════════════════════════════════════════ */
#define DECLARE_VECTOR(T) \
typedef struct STB_Vector_##T STB_Vector_##T; \
struct STB_Vector_##T { \
T *data; \
size_t _size; \
size_t _capacity; \
unsigned int magic; \
STB_VectorErrorHandler error; \
void (*push_back)(T value); \
T (*get)(int index); \
T (*at)(int index); \
void (*set)(int index, T value); \
void (*resize)(size_t new_size); \
void (*reserve)(size_t capacity); \
size_t (*size)(void); \
size_t (*capacity)(void); \
void (*clear)(void); \
int (*empty)(void); \
void (*destroy)(void); \
void (*pop_back)(void); \
T (*front)(void); \
T (*back)(void); \
T *(*data_ptr)(void); \
void (*insert)(int index, T value); \
void (*erase)(int index); \
void (*swap)(STB_Vector_##T *other); \
void (*shrink_to_fit)(void); \
size_t (*max_size)(void); \
}; \
\
static void _stb_vec_throw_##T(STB_VectorErrorCode code, const char *msg) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
if (!vec || !vec->error.active) { \
fprintf(stderr, "FATAL: %s\n", msg); \
exit(EXIT_FAILURE); \
} \
vec->error.code = code; \
strncpy(vec->error.message, msg, 255); \
vec->error.message[255] = '\0'; \
longjmp(vec->error.env, code); \
} \
\
static void _stb_vec_validate_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
if (!vec || vec->magic != STB_VECTOR_MAGIC) { \
fprintf(stderr, "FATAL: Invalid or corrupted vector\n"); \
exit(EXIT_FAILURE); \
} \
} \
\
static void _stb_vec_range_check_##T(int index) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
if (index < 0 || (size_t)index >= vec->_size) { \
char buf[256]; \
snprintf(buf, 256, "vector::range_check: index %d out of bounds (size %zu)", index, vec->_size); \
_stb_vec_throw_##T(STB_VEC_ERR_OUT_OF_BOUNDS, buf); \
} \
} \
\
static size_t _stb_vec_max_size_##T(void) { \
size_t alloc_max = SIZE_MAX / sizeof(T); \
size_t diff_max = (size_t)PTRDIFF_MAX; \
return (alloc_max < diff_max) ? alloc_max : diff_max; \
} \
\
static void _stb_vec_check_length_##T(size_t n) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
size_t max_sz = _stb_vec_max_size_##T(); \
if (n > max_sz) { \
char buf[256]; \
snprintf(buf, 256, "vector::check_length: requested size %zu exceeds maximum %zu", n, max_sz); \
_stb_vec_throw_##T(STB_VEC_ERR_LENGTH_ERROR, buf); \
} \
} \
\
static void _stb_vec_push_back_##T(T value) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
if (vec->_size >= vec->_capacity) { \
size_t new_cap = vec->_capacity ? vec->_capacity * STB_VECTOR_GROWTH_FACTOR : STB_VECTOR_INITIAL_CAPACITY; \
_stb_vec_check_length_##T(new_cap); \
T *temp = (T *)STB_VECTOR_REALLOC(vec->data, new_cap * sizeof(T), NULL); \
if (!temp) _stb_vec_throw_##T(STB_VEC_ERR_ALLOCATION_FAILED, "push_back: memory allocation failed"); \
vec->data = temp; \
vec->_capacity = new_cap; \
} \
vec->data[vec->_size++] = value; \
} \
\
static T _stb_vec_get_##T(int index) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
_stb_vec_range_check_##T(index); \
return vec->data[index]; \
} \
\
static void _stb_vec_set_##T(int index, T value) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
_stb_vec_range_check_##T(index); \
vec->data[index] = value; \
} \
\
static void _stb_vec_resize_##T(size_t new_size) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
_stb_vec_check_length_##T(new_size); \
if (new_size > vec->_capacity) { \
T *temp = (T *)STB_VECTOR_REALLOC(vec->data, new_size * sizeof(T), NULL); \
if (!temp) _stb_vec_throw_##T(STB_VEC_ERR_ALLOCATION_FAILED, "resize: memory allocation failed"); \
vec->data = temp; \
vec->_capacity = new_size; \
} \
if (new_size > vec->_size) { \
memset(vec->data + vec->_size, 0, (new_size - vec->_size) * sizeof(T)); \
} \
vec->_size = new_size; \
} \
\
static void _stb_vec_reserve_##T(size_t new_cap) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
_stb_vec_check_length_##T(new_cap); \
if (new_cap > vec->_capacity) { \
T *temp = (T *)STB_VECTOR_REALLOC(vec->data, new_cap * sizeof(T), NULL); \
if (!temp) _stb_vec_throw_##T(STB_VEC_ERR_ALLOCATION_FAILED, "reserve: memory allocation failed"); \
vec->data = temp; \
vec->_capacity = new_cap; \
} \
} \
\
static size_t _stb_vec_size_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
return vec->_size; \
} \
\
static size_t _stb_vec_capacity_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
return vec->_capacity; \
} \
\
static void _stb_vec_clear_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
vec->_size = 0; \
} \
\
static int _stb_vec_empty_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
return vec->_size == 0; \
} \
\
static void _stb_vec_destroy_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
if (!vec) return; \
if (vec->data) { STB_VECTOR_FREE(vec->data, NULL); vec->data = NULL; } \
vec->_size = 0; \
vec->_capacity = 0; \
vec->magic = 0; \
} \
\
static void _stb_vec_pop_back_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
if (vec->_size == 0) _stb_vec_throw_##T(STB_VEC_ERR_OUT_OF_BOUNDS, "pop_back: vector is empty"); \
vec->_size--; \
memset(&vec->data[vec->_size], 0, sizeof(T)); \
} \
\
static T _stb_vec_front_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
if (vec->_size == 0) _stb_vec_throw_##T(STB_VEC_ERR_OUT_OF_BOUNDS, "front: vector is empty"); \
return vec->data[0]; \
} \
\
static T _stb_vec_back_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
if (vec->_size == 0) _stb_vec_throw_##T(STB_VEC_ERR_OUT_OF_BOUNDS, "back: vector is empty"); \
return vec->data[vec->_size - 1]; \
} \
\
static T *_stb_vec_data_ptr_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
return vec->data; \
} \
\
static void _stb_vec_insert_##T(int index, T value) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
if (index < 0 || (size_t)index > vec->_size) { \
char buf[256]; \
snprintf(buf, 256, "vector::insert: index %d out of range (size %zu)", index, vec->_size); \
_stb_vec_throw_##T(STB_VEC_ERR_OUT_OF_BOUNDS, buf); \
} \
size_t uindex = (size_t)index; \
if (vec->_size >= vec->_capacity) { \
size_t new_cap = vec->_capacity ? vec->_capacity * STB_VECTOR_GROWTH_FACTOR : STB_VECTOR_INITIAL_CAPACITY; \
_stb_vec_check_length_##T(new_cap); \
T *temp = (T *)STB_VECTOR_REALLOC(vec->data, new_cap * sizeof(T), NULL); \
if (!temp) _stb_vec_throw_##T(STB_VEC_ERR_ALLOCATION_FAILED, "insert: memory allocation failed"); \
vec->data = temp; \
vec->_capacity = new_cap; \
} \
if (uindex < vec->_size) { \
memmove(&vec->data[uindex + 1], &vec->data[uindex], (vec->_size - uindex) * sizeof(T)); \
} \
vec->data[uindex] = value; \
vec->_size++; \
} \
\
static void _stb_vec_erase_##T(int index) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
if (index < 0 || (size_t)index >= vec->_size) { \
char buf[256]; \
snprintf(buf, 256, "vector::erase: index %d out of range (size %zu)", index, vec->_size); \
_stb_vec_throw_##T(STB_VEC_ERR_OUT_OF_BOUNDS, buf); \
} \
size_t uindex = (size_t)index; \
if (uindex + 1 < vec->_size) { \
memmove(&vec->data[uindex], &vec->data[uindex + 1], (vec->_size - uindex - 1) * sizeof(T)); \
} \
vec->_size--; \
memset(&vec->data[vec->_size], 0, sizeof(T)); \
} \
\
static void _stb_vec_swap_##T(STB_Vector_##T *other) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
if (!other) _stb_vec_throw_##T(STB_VEC_ERR_INVALID_VECTOR, "swap: other vector is NULL"); \
_stb_vec_validate_##T(); \
if (other->magic != STB_VECTOR_MAGIC) _stb_vec_throw_##T(STB_VEC_ERR_INVALID_VECTOR, "swap: other vector is invalid"); \
T *tmp_data = vec->data; \
size_t tmp_size = vec->_size; \
size_t tmp_cap = vec->_capacity; \
vec->data = other->data; \
vec->_size = other->_size; \
vec->_capacity = other->_capacity; \
other->data = tmp_data; \
other->_size = tmp_size; \
other->_capacity = tmp_cap; \
} \
\
static void _stb_vec_shrink_to_fit_##T(void) { \
STB_Vector_##T *vec = (STB_Vector_##T *)_stb_vec_ctx_current; \
_stb_vec_validate_##T(); \
if (vec->_capacity <= vec->_size) return; \
if (vec->_size == 0) { \
STB_VECTOR_FREE(vec->data, NULL); \
vec->data = NULL; \
vec->_capacity = 0; \
return; \
} \
T *temp = (T *)STB_VECTOR_REALLOC(vec->data, vec->_size * sizeof(T), NULL); \
if (!temp) _stb_vec_throw_##T(STB_VEC_ERR_ALLOCATION_FAILED, "shrink_to_fit: memory allocation failed"); \
vec->data = temp; \
vec->_capacity = vec->_size; \
} \
\
static STB_Vector_##T *_stb_vec_create_##T(size_t capacity, void *ctx) { \
STB_Vector_##T *vec = (STB_Vector_##T *)STB_VECTOR_MALLOC(sizeof(STB_Vector_##T), ctx); \
if (!vec || capacity > STB_VECTOR_MAX_SIZE(T)) { \
fprintf(stderr, "FATAL: Vector allocation failed (type: %s, capacity: %zu)\n", #T, capacity); \
exit(EXIT_FAILURE); \
} \
vec->_size = 0; \
vec->_capacity = 0; \
vec->magic = STB_VECTOR_MAGIC; \
vec->data = NULL; \
vec->error.active = 1; \
vec->error.code = STB_VEC_ERR_NONE; \
memset(vec->error.message, 0, 256); \
vec->push_back = _stb_vec_push_back_##T; \
vec->get = _stb_vec_get_##T; \
vec->at = _stb_vec_get_##T; \
vec->set = _stb_vec_set_##T; \
vec->resize = _stb_vec_resize_##T; \
vec->reserve = _stb_vec_reserve_##T; \
vec->size = _stb_vec_size_##T; \
vec->capacity = _stb_vec_capacity_##T; \
vec->clear = _stb_vec_clear_##T; \
vec->empty = _stb_vec_empty_##T; \
vec->destroy = _stb_vec_destroy_##T; \
vec->pop_back = _stb_vec_pop_back_##T; \
vec->front = _stb_vec_front_##T; \
vec->back = _stb_vec_back_##T; \
vec->data_ptr = _stb_vec_data_ptr_##T; \
vec->insert = _stb_vec_insert_##T; \
vec->erase = _stb_vec_erase_##T; \
vec->swap = _stb_vec_swap_##T; \
vec->shrink_to_fit = _stb_vec_shrink_to_fit_##T; \
vec->max_size = _stb_vec_max_size_##T; \
_stb_vec_ctx_current = vec; \
_stb_vec_ctx_##T = vec; \
if (capacity > 0) { \
_stb_vec_check_length_##T(capacity); \
vec->data = (T *)STB_VECTOR_MALLOC(capacity * sizeof(T), ctx); \
if (!vec->data) { \
STB_VECTOR_FREE(vec, ctx); \
fprintf(stderr, "FATAL: Vector data allocation failed (type: %s)\n", #T); \
exit(EXIT_FAILURE); \
} \
memset(vec->data, 0, capacity * sizeof(T)); \
vec->_capacity = capacity; \
} \
return vec; \
} \
\
static STB_Vector_##T *_stb_vec_create_size_##T(size_t size, void *ctx) { \
STB_Vector_##T *vec = _stb_vec_create_##T(size, ctx); \
vec->_size = size; \
return vec; \
} \
\
static STB_Vector_##T *_stb_vec_create_fill_##T(size_t size, T fill_value, void *ctx) { \
STB_Vector_##T *vec = _stb_vec_create_##T(size, ctx); \
vec->_size = size; \
if (size > 0) { \
for (size_t i = 0; i < size; i++) { \
vec->data[i] = fill_value; \
} \
} \
return vec; \
}
/* Instantiate all types */
DECLARE_VECTOR(int)
DECLARE_VECTOR(float)
DECLARE_VECTOR(double)
DECLARE_VECTOR(char)
DECLARE_VECTOR(long)
#endif /* STB_VECTOR_IMPLEMENTATION */
#ifdef __cplusplus
}
#endif
@haseeb-heaven
Copy link
Author

haseeb-heaven commented Oct 31, 2025

Example of Vector Int.

#define STB_VECTOR_IMPLEMENTATION
#include "stb_vector.h"

void print(Vector(int)* vec, const char* name)
{
	printf("%s: size=%zu, capacity=%zu, elements=[", name, $(vec)->size(), $(vec)->capacity());
	for (size_t index = 0; index < $(vec)->size(); ++index) {
		printf("%d", $(vec)->get(index));
		if (index + 1 < $(vec)->size()) {
			printf(", ");
		}
	}
	printf("]\n");
}

int main(void)
{
    printf("=== FULL INT VECTOR EXAMPLE (All Operations + Try/Catch) ===\n");

    // Create a new integer vector
    Vector(int)* int_vec = vector_new(int, 3, 10);
    print(int_vec, "int_vec");

    /* ─────────────────────────────────────────── */
    /* 1. PUSH_BACK                               */
    /* ─────────────────────────────────────────── */
    printf("\n[1] push_back:\n");
    $(int_vec)->push_back(100);
    $(int_vec)->push_back(200);
    $(int_vec)->push_back(300);
    print(int_vec, "int_vec");

    /* ─────────────────────────────────────────── */
    /* 2. INSERT                                  */
    /* ─────────────────────────────────────────── */
    printf("\n[2] insert(1, 999):\n");
    $(int_vec)->insert(1, 999);
    print(int_vec, "int_vec");

    /* ─────────────────────────────────────────── */
    /* 3. ERASE                                   */
    /* ─────────────────────────────────────────── */
    printf("\n[3] erase(2):\n");
    $(int_vec)->erase(2);
    print(int_vec, "int_vec");

    /* ─────────────────────────────────────────── */
    /* 4. FRONT / BACK                            */
    /* ─────────────────────────────────────────── */
    printf("\n[4] front/back:\n");
    printf("  front() = %d\n", $(int_vec)->front());
    printf("  back()  = %d\n", $(int_vec)->back());

    /* ─────────────────────────────────────────── */
    /* 5. GET / AT / SET                          */
    /* ─────────────────────────────────────────── */
    printf("\n[5] get/at/set:\n");
    printf("  get(1) = %d\n", $(int_vec)->get(1));
    printf("  at(1)  = %d\n", $(int_vec)->at(1));
    $(int_vec)->set(1, 555);
    print(int_vec, "int_vec (after set)");

    /* ─────────────────────────────────────────── */
    /* 6. RESIZE / RESERVE                        */
    /* ─────────────────────────────────────────── */
    printf("\n[6] resize / reserve:\n");
    $(int_vec)->resize(8);
    print(int_vec, "int_vec (resized to 8)");
    $(int_vec)->reserve(16);
    printf("  capacity after reserve(16): %zu\n", $(int_vec)->capacity());

    /* ─────────────────────────────────────────── */
    /* 7. SHRINK_TO_FIT                           */
    /* ─────────────────────────────────────────── */
    printf("\n[7] shrink_to_fit:\n");
    $(int_vec)->shrink_to_fit();
    printf("  capacity after shrink_to_fit: %zu\n", $(int_vec)->capacity());

    /* ─────────────────────────────────────────── */
    /* 8. SIZE / CAPACITY / MAX_SIZE              */
    /* ─────────────────────────────────────────── */
    printf("\n[8] size/capacity/max_size:\n");
    printf("  size      = %zu\n", $(int_vec)->size());
    printf("  capacity  = %zu\n", $(int_vec)->capacity());
    printf("  max_size  = %zu\n", $(int_vec)->max_size());

    /* ─────────────────────────────────────────── */
    /* 9. DATA_PTR                                */
    /* ─────────────────────────────────────────── */
    printf("\n[9] data_ptr:\n");
    int* ptr = $(int_vec)->data_ptr();
    printf("  raw pointer: %p\n", (void*)ptr);
    printf("  ptr[0] = %d, ptr[1] = %d\n", ptr[0], ptr[1]);

    /* ─────────────────────────────────────────── */
    /* 10. SWAP                                   */
    /* ─────────────────────────────────────────── */
    printf("\n[10] swap:\n");
    Vector(int)* other_vec = vector_new(int, 2, 9999);
    printf("  Before swap:\n");
    print(int_vec, "int_vec");
    print(other_vec, "other_vec");
    $(int_vec)->swap(other_vec);
    printf("  After swap:\n");
    print(int_vec, "int_vec");
    print(other_vec, "other_vec");

    /* ─────────────────────────────────────────── */
    /* 11. POP_BACK                               */
    /* ─────────────────────────────────────────── */
    printf("\n[11] pop_back:\n");
    $(int_vec)->pop_back();
    print(int_vec, "int_vec");

    /* ─────────────────────────────────────────── */
    /* 12. CLEAR / EMPTY                          */
    /* ─────────────────────────────────────────── */
    printf("\n[12] clear/empty:\n");
    $(int_vec)->clear();
    print(int_vec, "int_vec (after clear)");
    printf("  empty() = %d\n", $(int_vec)->empty());

    /* ─────────────────────────────────────────── */
    /* 13. INVALID ACCESS (try/catch)             */
    /* ─────────────────────────────────────────── */
    printf("\n[13] INVALID ACCESS TESTS:\n");

    stb_try(int_vec) {
        printf("→ at(-1):\n");
        int x = $(int_vec)->at(-1);
        printf("  value: %d\n", x);
    }
    stb_catch {
        printf("  Exception: %s\n", int_vec->error.message);
    }

    stb_try(int_vec) {
        printf("\n→ at(999):\n");
        int x = $(int_vec)->at(999);
        printf("  value: %d\n", x);
    }
    stb_catch {
        printf("  Exception: %s\n", int_vec->error.message);
    }

    /* ─────────────────────────────────────────── */
    /* 14. DESTROY / FREE                         */
    /* ─────────────────────────────────────────── */
    printf("\n[14] destroy:\n");
    $(int_vec)->destroy();
    $(other_vec)->destroy();
    free(int_vec);
    free(other_vec);

    printf("\n=== ALL OPERATIONS COMPLETED SUCCESSFULLY ✅ ===\n");
    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment