├── .gitmodules ├── examples ├── include │ └── z_registry.h ├── c │ ├── scheduler.c │ │ ├── my_vectors.h │ │ └── scheduler.c │ ├── example_3_safe.c │ ├── example_0.c │ ├── example_portable_0.c │ ├── example_0_safe.c │ ├── example_2_safe.c │ ├── example_2.c │ ├── example_1.c │ ├── example_portable_2.c │ ├── example_portable_1.c │ ├── example_1_safe.c │ ├── example_3.c │ └── example_portable_3.c ├── cpp │ └── example_0.cpp └── README.md ├── LICENSE ├── Makefile ├── .github └── workflows │ └── build.yml ├── tests ├── test_cpp.cpp └── test_main.c ├── README.md ├── src └── zvec.c └── zvec.h /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "z-core"] 2 | path = z-core 3 | url = https://github.com/z-libs/z-core.git 4 | -------------------------------------------------------------------------------- /examples/include/z_registry.h: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED BY Z-SCANNER - DO NOT EDIT */ 2 | #ifndef Z_REGISTRY_H 3 | #define Z_REGISTRY_H 4 | 5 | /* Vectors */ 6 | #define Z_AUTOGEN_VECS(X) \ 7 | X(int, Int) \ 8 | X(Point, Point) \ 9 | 10 | /* Lists */ 11 | #define Z_AUTOGEN_LISTS(X) \ 12 | 13 | /* Maps */ 14 | #define Z_AUTOGEN_MAPS(X) \ 15 | 16 | #endif // Z_REGISTRY_H 17 | -------------------------------------------------------------------------------- /examples/c/scheduler.c/my_vectors.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MY_VECTORS_H 3 | #define MY_VECTORS_H 4 | 5 | #include "zvec.h" 6 | 7 | typedef struct 8 | { 9 | int id; 10 | int priority; // 0 = Low, 100 = Critical 11 | char payload[1024]; // Heavy data chunk (1KB) 12 | } Task; 13 | 14 | #define REGISTER_TYPES(X) \ 15 | X(int, int) \ 16 | X(Task, Task) 17 | 18 | REGISTER_TYPES(DEFINE_VEC_TYPE) 19 | 20 | #endif -------------------------------------------------------------------------------- /examples/c/example_3_safe.c: -------------------------------------------------------------------------------- 1 | 2 | #define Z_SHORT_ERR 3 | #define ZERROR_IMPLEMENTATION 4 | #include "zerror.h" 5 | #define ZVEC_SHORT_NAMES 6 | #include "zvec.h" 7 | 8 | DEFINE_VEC_TYPE(int, Int) 9 | 10 | Res_Int get_third_item(vec_Int* v) 11 | { 12 | int val = try(vec_at_safe(v, 2)); 13 | return Res_Int_ok(val); 14 | } 15 | 16 | zres process_data() 17 | { 18 | vec_autofree(Int) nums = vec_init(Int); 19 | 20 | check_ctx(vec_push_safe(&nums, 20), "Failed to push 20"); 21 | check_ctx(vec_push_safe(&nums, 30), "Failed to push 30"); 22 | 23 | int x = try_into(zres, vec_at_safe(&nums, 0)); 24 | (void)x; 25 | 26 | unwrap(vec_at_safe(&nums, 99)); 27 | 28 | return zres_ok(); 29 | } 30 | 31 | int main(void) 32 | { 33 | run(process_data()); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /examples/c/example_0.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | typedef struct 5 | { 6 | float x, y; 7 | } Point; 8 | 9 | #define ZVEC_SHORT_NAMES 10 | #include "zvec.h" 11 | 12 | DEFINE_VEC_TYPE(int, Int) 13 | DEFINE_VEC_TYPE(Point, Point) 14 | 15 | int main(void) 16 | { 17 | vec(Int) nums = vec_init(Int); 18 | 19 | vec_push(&nums, 10); 20 | vec_push(&nums, 20); 21 | vec_push(&nums, 30); 22 | 23 | printf("Integers: "); 24 | vec_foreach(&nums, ptr) 25 | { 26 | printf("%d ", *ptr); 27 | } 28 | printf("\n"); 29 | 30 | vec(Point) points = vec_init(Point); 31 | vec_push(&points, ((Point){1.5f, 2.5f})); 32 | 33 | Point *p0 = vec_at(&points, 0); 34 | if(p0) 35 | { 36 | printf("Point 0: {x: %.1f, y: %.1f}\n", p0->x, p0->y); 37 | } 38 | 39 | vec_free(&nums); 40 | vec_free(&points); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /examples/c/example_portable_0.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | typedef struct 5 | { 6 | float x, y; 7 | } Point; 8 | 9 | #define ZVEC_SHORT_NAMES 10 | #include "zvec.h" 11 | 12 | DEFINE_VEC_TYPE(int, Int) 13 | DEFINE_VEC_TYPE(Point, Point) 14 | 15 | int main(void) 16 | { 17 | vec(Int) nums = vec_init(Int); 18 | 19 | vec_push(&nums, 10); 20 | vec_push(&nums, 20); 21 | vec_push(&nums, 30); 22 | 23 | printf("Integers: "); 24 | 25 | int *ptr; 26 | vec_foreach(&nums, ptr) 27 | { 28 | printf("%d ", *ptr); 29 | } 30 | printf("\n"); 31 | 32 | vec(Point) points = vec_init(Point); 33 | vec_push(&points, ((Point){1.5f, 2.5f})); 34 | 35 | Point *p0 = vec_at(&points, 0); 36 | if(p0) 37 | { 38 | printf("Point 0: {x: %.1f, y: %.1f}\n", p0->x, p0->y); 39 | } 40 | 41 | vec_free(&nums); 42 | vec_free(&points); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /examples/c/example_0_safe.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #define ZERROR_IMPLEMENTATION 4 | #define Z_SHORT_ERR 5 | #include "zerror.h" 6 | #define ZVEC_SHORT_NAMES 7 | #include "zvec.h" 8 | 9 | DEFINE_VEC_TYPE(int, Int) 10 | 11 | zres populate_and_print(void) 12 | { 13 | printf("[*] Starting safe vector operations...\n"); 14 | 15 | vec_autofree(Int) v = vec_init(Int); 16 | 17 | check( vec_push_safe(&v, 100) ); 18 | check( vec_push_safe(&v, 200) ); 19 | check( vec_push_safe(&v, 300) ); 20 | 21 | printf("[*] Vector size: %zu\n", v.length); 22 | 23 | int val = try_into(zres, vec_pop_safe(&v)); 24 | printf(" Popped: %d\n", val); 25 | 26 | int first = try_into(zres, vec_at_safe(&v, 0)); 27 | printf(" Index 0: %d\n", first); 28 | 29 | printf("[*] Attempting out-of-bounds access...\n"); 30 | 31 | int bad = try_into(zres, vec_at_safe(&v, 99)); 32 | 33 | printf(" Index 99: %d\n", bad); 34 | 35 | return zres_ok(); 36 | } 37 | 38 | int main(void) 39 | { 40 | return run(populate_and_print()); 41 | } 42 | -------------------------------------------------------------------------------- /examples/c/example_2_safe.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #define ZERROR_IMPLEMENTATION 4 | #define Z_SHORT_ERR 5 | #include "zerror.h" 6 | #define ZVEC_SHORT_NAMES 7 | #include "zvec.h" 8 | 9 | DEFINE_VEC_TYPE(int, Int) 10 | 11 | zres populate_and_print(void) 12 | { 13 | printf("[*] Starting safe vector operations...\n"); 14 | 15 | vec_autofree(Int) v = vec_init(Int); 16 | 17 | check( vec_reserve_safe(&v, 4) ); 18 | 19 | check( vec_push_safe(&v, 100) ); 20 | check( vec_push_safe(&v, 200) ); 21 | check( vec_push_safe(&v, 300) ); 22 | 23 | printf("[*] Vector size: %zu\n", v.length); 24 | 25 | int val = try_into(zres, vec_pop_safe(&v)); 26 | printf(" Popped: %d\n", val); 27 | 28 | int first = try_into(zres, vec_at_safe(&v, 0)); 29 | printf(" Index 0: %d\n", first); 30 | 31 | printf("[*] Attempting out-of-bounds access...\n"); 32 | 33 | int bad = try_or( vec_at_safe(&v, 99), -1 ); 34 | 35 | printf(" Index 99: %d\n", bad); 36 | 37 | return zres_ok(); 38 | } 39 | 40 | int main(void) 41 | { 42 | return run(populate_and_print()); 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Zuhaitz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/cpp/example_0.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | struct Point 6 | { 7 | float x, y; 8 | }; 9 | 10 | #define Z_AUTOGEN_VECS(X) \ 11 | X(int, Int) \ 12 | X(Point, Point) 13 | 14 | #include "zvec.h" 15 | 16 | int main() 17 | { 18 | std::cout << "=> Integers\n"; 19 | 20 | z_vec::vector nums = {10, 20, 30}; 21 | 22 | nums.push_back(40); 23 | 24 | std::cout << "Values: "; 25 | for (int x : nums) 26 | { 27 | std::cout << x << " "; 28 | } 29 | std::cout << "\n\n"; 30 | 31 | std::cout << "=> Points\n"; 32 | 33 | z_vec::vector points; 34 | 35 | points.push_back({1.5f, 2.5f}); 36 | points.push_back({3.0f, 4.0f}); 37 | 38 | for (const auto& p : points) 39 | { 40 | std::cout << "Point: {x: " << p.x << ", y: " << p.y << "}\n"; 41 | } 42 | 43 | try 44 | { 45 | points.at(0).x = 99.9f; 46 | std::cout << "Modified Point 0 x: " << points[0].x << "\n"; 47 | } catch (const std::exception& e) 48 | { 49 | std::cout << "Error: " << e.what() << "\n"; 50 | } 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | BUNDLER = z-core/zbundler.py 3 | SRC = src/zvec.c 4 | DIST = zvec.h 5 | 6 | CC = gcc 7 | CXX = g++ 8 | CFLAGS = -Wall -Wextra -std=c11 -O2 -I. 9 | CXXFLAGS = -Wall -Wextra -std=c++11 -O2 -I. 10 | 11 | all: bundle get_zerror_h 12 | 13 | bundle: 14 | @echo "Bundling $(DIST)..." 15 | python3 $(BUNDLER) $(SRC) $(DIST) 16 | 17 | get_zerror_h: 18 | @echo "Using wget to add 'zerror.h'..." 19 | wget -q "https://raw.githubusercontent.com/z-libs/zerror.h/main/zerror.h" -O "zerror.h" 20 | 21 | clean: 22 | @echo "Removing 'zerror.h'..." 23 | @rm zerror.h 24 | 25 | init: 26 | git submodule update --init --recursive 27 | 28 | 29 | test: bundle get_zerror_h test_c test_cpp clean 30 | 31 | test_c: 32 | @echo "----------------------------------------" 33 | @echo "Building C Tests..." 34 | @$(CC) $(CFLAGS) tests/test_main.c -o tests/runner_c 35 | @./tests/runner_c 36 | @rm tests/runner_c 37 | 38 | test_cpp: 39 | @echo "----------------------------------------" 40 | @echo "Building C++ Tests..." 41 | @$(CXX) $(CXXFLAGS) tests/test_cpp.cpp -o tests/runner_cpp 42 | @./tests/runner_cpp 43 | @rm tests/runner_cpp 44 | 45 | .PHONY: all bundle get_zerror_h init test test_c test_cpp clean 46 | -------------------------------------------------------------------------------- /examples/c/example_2.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | typedef struct 5 | { 6 | float x, y; 7 | } Point; 8 | 9 | #define REGISTER_ZVEC_TYPES(X) \ 10 | X(int, Int) \ 11 | X(Point, Point) 12 | 13 | #define ZVEC_SHORT_NAMES 14 | #include "zvec.h" 15 | 16 | int compare_ints(const int *a, const int *b) 17 | { 18 | return (*a > *b) - (*a < *b); 19 | } 20 | 21 | int compare_points_x(const Point *a, const Point *b) 22 | { 23 | if (a->x < b->x) return -1; 24 | if (a->x > b->x) return 1; 25 | return 0; 26 | } 27 | 28 | int main(void) 29 | { 30 | vec(Int) nums = vec_init(Int); 31 | vec_push(&nums, 42); 32 | vec_push(&nums, 7); 33 | vec_push(&nums, 19); 34 | vec_push(&nums, 1); 35 | 36 | printf("Before sort: "); 37 | vec_foreach(&nums, n) printf("%d ", *n); 38 | printf("\n"); 39 | 40 | vec_sort(&nums, compare_ints); 41 | 42 | printf("After sort: "); 43 | vec_foreach(&nums, n) printf("%d ", *n); 44 | printf("\n\n"); 45 | 46 | vec(Point) points = vec_init(Point); 47 | vec_push(&points, ((Point){10.0f, 2.0f})); 48 | vec_push(&points, ((Point){3.5f, 1.0f})); 49 | vec_push(&points, ((Point){7.0f, 5.0f})); 50 | 51 | printf("Points before sort (by X):\n"); 52 | vec_foreach(&points, p) printf("{%.1f, %.1f} ", p->x, p->y); 53 | printf("\n"); 54 | 55 | vec_sort(&points, compare_points_x); 56 | 57 | printf("Points after sort (by X):\n"); 58 | vec_foreach(&points, p) printf("{%.1f, %.1f} ", p->x, p->y); 59 | printf("\n"); 60 | 61 | vec_free(&nums); 62 | vec_free(&points); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /examples/c/example_1.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | typedef struct 5 | { 6 | float x, y; 7 | } Point; 8 | 9 | #define REGISTER_ZVEC_TYPES(X) \ 10 | X(int, Int) \ 11 | X(Point, Point) 12 | 13 | #define ZVEC_SHORT_NAMES 14 | #include "zvec.h" 15 | 16 | int main(void) 17 | { 18 | printf("*Integer example*\n"); 19 | vec(Int) nums = vec_init(Int); 20 | 21 | vec_push(&nums, 100); 22 | vec_push(&nums, 200); 23 | vec_push(&nums, 300); 24 | vec_push(&nums, 400); 25 | 26 | printf("Before remove: "); 27 | vec_foreach(&nums, n) 28 | { 29 | printf("%d ", *n); 30 | } 31 | printf("\n"); 32 | 33 | printf("Removing index 1 (ordered)...\n"); 34 | vec_remove(&nums, 1); 35 | 36 | printf("After remove: "); 37 | vec_foreach(&nums, n) 38 | { 39 | printf("%d ", *n); 40 | } 41 | printf("\n\n"); 42 | 43 | printf("*Point example*\n"); 44 | vec(Point) points = vec_init(Point); 45 | 46 | vec_push(&points, ((Point){1.0f, 1.0f})); 47 | vec_push(&points, ((Point){2.0f, 2.0f})); 48 | vec_push(&points, ((Point){3.0f, 3.0f})); 49 | vec_push(&points, ((Point){4.0f, 4.0f})); 50 | 51 | int i = 0; 52 | vec_foreach(&points, p) 53 | { 54 | printf("[%d] {x:%.1f, y:%.1f}\n", i++, p->x, p->y); 55 | } 56 | 57 | printf("Swap removing index 1...\n"); 58 | vec_swap_remove(&points, 1); 59 | 60 | i = 0; 61 | vec_foreach(&points, p) 62 | { 63 | printf("[%d] {x:%.1f, y:%.1f}\n", i++, p->x, p->y); 64 | } 65 | 66 | vec_free(&nums); 67 | vec_free(&points); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /examples/c/example_portable_2.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | typedef struct 5 | { 6 | float x, y; 7 | } Point; 8 | 9 | #define REGISTER_ZVEC_TYPES(X) \ 10 | X(int, Int) \ 11 | X(Point, Point) 12 | 13 | #define ZVEC_SHORT_NAMES 14 | #include "zvec.h" 15 | 16 | int compare_ints(const int *a, const int *b) 17 | { 18 | return (*a > *b) - (*a < *b); 19 | } 20 | 21 | int compare_points_x(const Point *a, const Point *b) 22 | { 23 | if (a->x < b->x) return -1; 24 | if (a->x > b->x) return 1; 25 | return 0; 26 | } 27 | 28 | int main(void) 29 | { 30 | vec(Int) nums = vec_init(Int); 31 | vec_push(&nums, 42); 32 | vec_push(&nums, 7); 33 | vec_push(&nums, 19); 34 | vec_push(&nums, 1); 35 | 36 | printf("Before sort: "); 37 | int *n; 38 | vec_foreach(&nums, n) printf("%d ", *n); 39 | printf("\n"); 40 | 41 | vec_sort(&nums, compare_ints); 42 | 43 | printf("After sort: "); 44 | vec_foreach(&nums, n) printf("%d ", *n); 45 | printf("\n\n"); 46 | 47 | vec(Point) points = vec_init(Point); 48 | vec_push(&points, ((Point){10.0f, 2.0f})); 49 | vec_push(&points, ((Point){3.5f, 1.0f})); 50 | vec_push(&points, ((Point){7.0f, 5.0f})); 51 | 52 | printf("Points before sort (by X):\n"); 53 | Point *p; 54 | vec_foreach(&points, p) printf("{%.1f, %.1f} ", p->x, p->y); 55 | printf("\n"); 56 | 57 | vec_sort(&points, compare_points_x); 58 | 59 | printf("Points after sort (by X):\n"); 60 | vec_foreach(&points, p) printf("{%.1f, %.1f} ", p->x, p->y); 61 | printf("\n"); 62 | 63 | vec_free(&nums); 64 | vec_free(&points); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /examples/c/example_portable_1.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | typedef struct 5 | { 6 | float x, y; 7 | } Point; 8 | 9 | #define REGISTER_ZVEC_TYPES(X) \ 10 | X(int, Int) \ 11 | X(Point, Point) 12 | 13 | #define ZVEC_SHORT_NAMES 14 | #include "zvec.h" 15 | 16 | int main(void) 17 | { 18 | printf("*Integer example*\n"); 19 | vec(Int) nums = vec_init(Int); 20 | 21 | vec_push(&nums, 100); 22 | vec_push(&nums, 200); 23 | vec_push(&nums, 300); 24 | vec_push(&nums, 400); 25 | 26 | printf("Before remove: "); 27 | int *n; 28 | vec_foreach(&nums, n) 29 | { 30 | printf("%d ", *n); 31 | } 32 | printf("\n"); 33 | 34 | printf("Removing index 1 (ordered)...\n"); 35 | vec_remove(&nums, 1); 36 | 37 | printf("After remove: "); 38 | vec_foreach(&nums, n) 39 | { 40 | printf("%d ", *n); 41 | } 42 | printf("\n\n"); 43 | 44 | printf("*Point example*\n"); 45 | vec(Point) points = vec_init(Point); 46 | 47 | vec_push(&points, ((Point){1.0f, 1.0f})); 48 | vec_push(&points, ((Point){2.0f, 2.0f})); 49 | vec_push(&points, ((Point){3.0f, 3.0f})); 50 | vec_push(&points, ((Point){4.0f, 4.0f})); 51 | 52 | int i = 0; 53 | Point *p; 54 | vec_foreach(&points, p) 55 | { 56 | printf("[%d] {x:%.1f, y:%.1f}\n", i++, p->x, p->y); 57 | } 58 | 59 | printf("Swap removing index 1...\n"); 60 | vec_swap_remove(&points, 1); 61 | 62 | i = 0; 63 | vec_foreach(&points, p) 64 | { 65 | printf("[%d] {x:%.1f, y:%.1f}\n", i++, p->x, p->y); 66 | } 67 | 68 | vec_free(&nums); 69 | vec_free(&points); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Examples 3 | 4 | This folder contains example usage for both C and C++. 5 | 6 | ## How to Compile 7 | 8 | Because `zvec` uses macro generation to create type-safe containers, there is a one-time setup step to register your types. 9 | 10 | 1. Inside `include/` either make your own registry header (like `my_vectors.h` or something similar), or use `zscanner.py`. 11 | 12 | 2. If you use the scanner, remember you can get it with: 13 | 14 | ```bash 15 | git submodule update --init --recursive 16 | ``` 17 | 18 | Then just do: 19 | 20 | ```bash 21 | python3 ../z-core/zscanner.py c/ include/z_registry.h 22 | ``` 23 | 24 | > Note: If you are compiling the C++ examples change `c/` to `cpp/` 25 | 26 | Expect an output like this: 27 | 28 | ```bash 29 | Scanning c/... 30 | Generating include/z_registry.h... 31 | Done. 32 | ``` 33 | 34 | `z_registry.h` should look similar to this: 35 | 36 | ```c 37 | /* AUTO-GENERATED BY Z-SCANNER - DO NOT EDIT */ 38 | #ifndef Z_REGISTRY_H 39 | #define Z_REGISTRY_H 40 | 41 | /* Vectors */ 42 | #define Z_AUTOGEN_VECS(X) \ 43 | X(int, Int) \ 44 | X(Point, Point) \ 45 | 46 | /* Lists */ 47 | #define Z_AUTOGEN_LISTS(X) \ 48 | 49 | /* Maps */ 50 | #define Z_AUTOGEN_MAPS(X) \ 51 | 52 | #endif // Z_REGISTRY_H 53 | ``` 54 | 55 | 3. To compile then you can simply do: 56 | 57 | **For C:** 58 | 59 | ```bash 60 | gcc c/example_0.c -I.. -Iinclude -o example_c 61 | ./example_c 62 | ``` 63 | 64 | **For C++:** 65 | 66 | ```bash 67 | g++ cpp/example_0.cpp -I.. -Iinclude -o example_cpp 68 | ./example_cpp 69 | ``` 70 | 71 | `-I..` is needed to include `zvec.h`. You can simply just move it, but this way we keep the current structure. `-Iinclude` includes the registry header. 72 | -------------------------------------------------------------------------------- /examples/c/example_1_safe.c: -------------------------------------------------------------------------------- 1 | 2 | typedef struct 3 | { 4 | int id; 5 | float temperature; 6 | } SensorData; 7 | 8 | #include 9 | #define ZERROR_IMPLEMENTATION 10 | #define Z_SHORT_ERR 11 | #include "zerror.h" 12 | #define ZVEC_SHORT_NAMES 13 | #include "zvec.h" 14 | 15 | DEFINE_VEC_TYPE(SensorData, Data) 16 | 17 | ResInt process_sensors(void) 18 | { 19 | printf("[*] Initializing Sensor Data...\n"); 20 | 21 | vec_autofree(Data) sensors = vec_init(Data); 22 | 23 | check_into( ResInt, vec_push_safe(&sensors, ((SensorData){101, 24.5f})) ); 24 | check_into( ResInt, vec_push_safe(&sensors, ((SensorData){102, 25.1f})) ); 25 | check_into( ResInt, vec_push_safe(&sensors, ((SensorData){103, 23.8f})) ); 26 | 27 | SensorData last = try_into( ResInt, vec_last_safe(&sensors) ); 28 | 29 | printf(" Last Reading: ID %d -> %.1f C\n", last.id, last.temperature); 30 | 31 | printf("[*] Processing items...\n"); 32 | int count = 0; 33 | while (!vec_is_empty(&sensors)) 34 | { 35 | SensorData item = try_into( ResInt, vec_pop_safe(&sensors) ); 36 | printf(" Processed ID: %d\n", item.id); 37 | count++; 38 | } 39 | 40 | printf("[*] Attempting to pop from empty vector...\n"); 41 | 42 | /* Deliberate error... this will return ResInt_err(...) up the stack. */ 43 | SensorData ghost = try_into( ResInt, vec_pop_safe(&sensors) ); 44 | 45 | printf("(!) This line is never reached! Got: %d\n", ghost.id); 46 | 47 | return ResInt_ok(count); 48 | } 49 | 50 | zres app_main(void) 51 | { 52 | int count = try_into(zres, process_sensors()); 53 | 54 | printf("Success! Processed %d items.\n", count); 55 | 56 | return zres_ok(); 57 | } 58 | 59 | int main(void) 60 | { 61 | return run(app_main()); 62 | } 63 | -------------------------------------------------------------------------------- /examples/c/scheduler.c/scheduler.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "my_vectors.h" 5 | 6 | int compare_priority_desc(const Task *a, const Task *b) 7 | { 8 | return b->priority - a->priority; 9 | } 10 | 11 | int compare_for_search(const Task *key, const Task *elem) 12 | { 13 | return elem->priority - key->priority; 14 | } 15 | 16 | int main(void) 17 | { 18 | printf("-> Initializing Job Queue...\n"); 19 | vec_Task queue = vec_from(Task, { 20 | {101, 50, "Regular Maintenance"}, 21 | {102, 99, "CRITICAL SERVER PATCH"}, 22 | {103, 10, "Log Rotation"} 23 | }); 24 | 25 | printf("-> Receiving Heavy Task (Zero-Copy)...\n"); 26 | 27 | Task *heavy = vec_push_slot(&queue); 28 | if (heavy) 29 | { 30 | heavy->id = 104; 31 | heavy->priority = 85; 32 | strcpy(heavy->payload, "Heavy Simulation Data [1KB]..."); 33 | } 34 | 35 | printf("-> Sorting by Priority (Descending)...\n"); 36 | vec_sort(&queue, compare_priority_desc); 37 | 38 | Task threshold_key = { .priority = 50 }; 39 | 40 | Task *cutoff = vec_lower_bound(&queue, &threshold_key, compare_for_search); 41 | 42 | long high_priority_count = cutoff - vec_data(&queue); 43 | 44 | printf("-> Found %ld High-Priority Tasks:\n", high_priority_count); 45 | 46 | for (int i = 0; i < high_priority_count; i++) 47 | { 48 | Task *t = vec_at(&queue, i); 49 | printf(" [EXEC] ID:%d (Prio:%d) - %s\n", t->id, t->priority, t->payload); 50 | } 51 | 52 | printf("-> Skipped Low-Priority Tasks:\n"); 53 | Task *it = cutoff; 54 | while (it < vec_last(&queue) + 1) 55 | { 56 | printf(" [SKIP] ID:%d (Prio:%d)\n", it->id, it->priority); 57 | it++; 58 | } 59 | 60 | vec_free(&queue); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Build and Sync 3 | 4 | on: 5 | push: 6 | branches: [ "main" ] 7 | pull_request: 8 | branches: [ "main" ] 9 | schedule: 10 | - cron: '0 0 * * *' 11 | workflow_dispatch: 12 | 13 | permissions: 14 | contents: write 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | with: 24 | submodules: recursive 25 | fetch-depth: 0 26 | 27 | - name: Set up Python 28 | uses: actions/setup-python@v4 29 | with: 30 | python-version: '3.x' 31 | 32 | - name: Update z-core submodule 33 | run: | 34 | git submodule update --remote --merge 35 | echo "Submodule updated to latest remote version." 36 | 37 | - name: Test Z-Scanner 38 | run: | 39 | echo "Running scanner on examples/..." 40 | mkdir -p include 41 | 42 | python3 z-core/zscanner.py examples/ include/z_registry.h 43 | 44 | if [ -f "include/z_registry.h" ]; then 45 | echo "Scanner successfully generated registry!" 46 | cat include/z_registry.h 47 | else 48 | echo "::error::Scanner failed to generate registry file." 49 | exit 1 50 | fi 51 | rm -rf include 52 | 53 | - name: Build Library 54 | run: make bundle 55 | 56 | - name: Run Unit Tests 57 | run: | 58 | echo "Running C and C++ Test Suites..." 59 | # Runs the 'test' target from your Makefile. 60 | # If it fails (non-zero exit), we print an error and exit. 61 | make test || { echo "::error::Unit tests failed! Check the logs above for assertion errors."; exit 1; } 62 | 63 | - name: Commit and Push changes 64 | uses: stefanzweifel/git-auto-commit-action@v5 65 | with: 66 | commit_message: "Auto-update: Bump z-core and regenerate zvec.h [skip ci]" 67 | file_pattern: '.' 68 | -------------------------------------------------------------------------------- /examples/c/example_3.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #define REGISTER_ZVEC_TYPES(X) \ 5 | X(int, Int) 6 | 7 | #define ZVEC_SHORT_NAMES 8 | #include "zvec.h" 9 | 10 | int compare_ints(const int *a, const int *b) 11 | { 12 | return (*a > *b) - (*a < *b); 13 | } 14 | 15 | int main(void) 16 | { 17 | vec(Int) nums = vec_init(Int); 18 | 19 | vec_push(&nums, 100); 20 | vec_push(&nums, 50); 21 | 22 | int bulk_data[] = { 10, 75, 25, 5 }; 23 | printf("[Extend] Adding {10, 75, 25, 5} to vector...\n"); 24 | 25 | vec_extend(&nums, bulk_data, 4); 26 | 27 | printf("Current Vector: "); 28 | vec_foreach(&nums, n) printf("%d ", *n); 29 | printf("\n\n"); 30 | 31 | printf("[Reverse] Reversing vector in-place...\n"); 32 | vec_reverse(&nums); 33 | 34 | printf("Reversed: "); 35 | vec_foreach(&nums, n) printf("%d ", *n); 36 | printf("\n\n"); 37 | 38 | printf("[Sort] Sorting vector...\n"); 39 | vec_sort(&nums, compare_ints); 40 | 41 | printf("Sorted: "); 42 | vec_foreach(&nums, n) printf("%d ", *n); 43 | printf("\n\n"); 44 | 45 | int key_found = 75; 46 | int key_missing = 99; 47 | 48 | printf("[Binary Search] Looking for values...\n"); 49 | 50 | int *res1 = vec_bsearch(&nums, &key_found, compare_ints); 51 | if (res1) 52 | { 53 | long index = res1 - vec_data(&nums); 54 | printf(" Key %d: Found at index %ld\n", key_found, index); 55 | } 56 | else 57 | { 58 | printf(" Key %d: Not found\n", key_found); 59 | } 60 | 61 | int *res2 = vec_bsearch(&nums, &key_missing, compare_ints); 62 | if (res2) 63 | { 64 | printf(" Key %d: Found\n", key_missing); 65 | } 66 | else 67 | { 68 | printf(" Key %d: Not found\n", key_missing); 69 | } 70 | printf("\n"); 71 | 72 | printf("[Data Access] Accessing raw array directly...\n"); 73 | int *raw_array = vec_data(&nums); 74 | printf(" raw_array[0] = %d\n", raw_array[0]); 75 | printf(" raw_array[1] = %d\n", raw_array[1]); 76 | 77 | vec_free(&nums); 78 | return 0; 79 | } -------------------------------------------------------------------------------- /examples/c/example_portable_3.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #define REGISTER_ZVEC_TYPES(X) \ 5 | X(int, Int) 6 | 7 | #define ZVEC_SHORT_NAMES 8 | #include "zvec.h" 9 | 10 | int compare_ints(const int *a, const int *b) 11 | { 12 | return (*a > *b) - (*a < *b); 13 | } 14 | 15 | int main(void) 16 | { 17 | vec(Int) nums = vec_init(Int); 18 | 19 | vec_push(&nums, 100); 20 | vec_push(&nums, 50); 21 | 22 | int bulk_data[] = { 10, 75, 25, 5 }; 23 | printf("[Extend] Adding {10, 75, 25, 5} to vector...\n"); 24 | 25 | vec_extend(&nums, bulk_data, 4); 26 | 27 | printf("Current Vector: "); 28 | int *n; 29 | vec_foreach(&nums, n) printf("%d ", *n); 30 | printf("\n\n"); 31 | 32 | printf("[Reverse] Reversing vector in-place...\n"); 33 | vec_reverse(&nums); 34 | 35 | printf("Reversed: "); 36 | vec_foreach(&nums, n) printf("%d ", *n); 37 | printf("\n\n"); 38 | 39 | printf("[Sort] Sorting vector...\n"); 40 | vec_sort(&nums, compare_ints); 41 | 42 | printf("Sorted: "); 43 | vec_foreach(&nums, n) printf("%d ", *n); 44 | printf("\n\n"); 45 | 46 | int key_found = 75; 47 | int key_missing = 99; 48 | 49 | printf("[Binary Search] Looking for values...\n"); 50 | 51 | int *res1 = vec_bsearch(&nums, &key_found, compare_ints); 52 | if (res1) 53 | { 54 | long index = res1 - vec_data(&nums); 55 | printf(" Key %d: Found at index %ld\n", key_found, index); 56 | } 57 | else 58 | { 59 | printf(" Key %d: Not found\n", key_found); 60 | } 61 | 62 | int *res2 = vec_bsearch(&nums, &key_missing, compare_ints); 63 | if (res2) 64 | { 65 | printf(" Key %d: Found\n", key_missing); 66 | } 67 | else 68 | { 69 | printf(" Key %d: Not found\n", key_missing); 70 | } 71 | printf("\n"); 72 | 73 | printf("[Data Access] Accessing raw array directly...\n"); 74 | int *raw_array = vec_data(&nums); 75 | printf(" raw_array[0] = %d\n", raw_array[0]); 76 | printf(" raw_array[1] = %d\n", raw_array[1]); 77 | 78 | vec_free(&nums); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /tests/test_cpp.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | struct Vec2 10 | { 11 | float x, y; 12 | 13 | // Operator overload for std::find / assertions. 14 | bool operator==(const Vec2& other) const 15 | { 16 | return x == other.x && y == other.y; 17 | } 18 | }; 19 | 20 | // Register std::string to test C++ memory management safety. 21 | #define REGISTER_ZVEC_TYPES(X) \ 22 | X(int, Int) \ 23 | X(Vec2, Vec2) \ 24 | X(std::string, String) 25 | 26 | #include "zvec.h" 27 | 28 | #define TEST(name) printf("[TEST] %-40s", name); 29 | #define PASS() std::cout << "\033[0;32mPASS\033[0m\n"; 30 | 31 | void test_constructors() 32 | { 33 | TEST("Constructors (Default, Cap, InitList)"); 34 | 35 | // Default. 36 | z_vec::vector v1; 37 | assert(v1.empty()); 38 | assert(v1.capacity() == 0); 39 | 40 | // Capacity. 41 | z_vec::vector v2(100); 42 | assert(v2.empty()); 43 | assert(v2.capacity() == 100); 44 | 45 | // Initializer List. 46 | z_vec::vector v3 = {1, 2, 3, 4, 5}; 47 | assert(v3.size() == 5); 48 | assert(v3[0] == 1); 49 | assert(v3[4] == 5); 50 | 51 | PASS(); 52 | } 53 | 54 | void test_rule_of_five() 55 | { 56 | TEST("Rule of 5 (Copy/Move Semantics)"); 57 | 58 | // Copy Constructor (Deep Copy). 59 | z_vec::vector original = {10, 20, 30}; 60 | z_vec::vector copy = original; 61 | 62 | assert(copy.size() == 3); 63 | assert(copy[0] == 10); 64 | assert(copy.data() != original.data()); // Must have distinct memory. 65 | 66 | // Modify copy, ensure original is untouched. 67 | copy[0] = 999; 68 | assert(original[0] == 10); 69 | 70 | // Move Constructor (Pointer Stealing). 71 | int* original_ptr = original.data(); 72 | z_vec::vector moved = std::move(original); 73 | 74 | assert(moved.data() == original_ptr); // Must steal pointer. 75 | assert(moved.size() == 3); 76 | assert(original.data() == nullptr); // Source must be empty. 77 | assert(original.size() == 0); 78 | 79 | // Move Assignment. 80 | z_vec::vector assigned; 81 | assigned = std::move(moved); 82 | assert(assigned.data() == original_ptr); 83 | assert(assigned.size() == 3); 84 | 85 | PASS(); 86 | } 87 | 88 | void test_stl_interop() 89 | { 90 | TEST("STL Compatibility (Iterators, Sort)"); 91 | 92 | z_vec::vector v = {50, 10, 40, 30, 20}; 93 | 94 | // Range-based for loop. 95 | int count = 0; 96 | for (int x : v) 97 | { 98 | count++; 99 | (void)x; 100 | } 101 | assert(count == 5); 102 | 103 | // std::sort (Works because iterators are pointers). 104 | std::sort(v.begin(), v.end()); 105 | 106 | assert(v[0] == 10); 107 | assert(v[4] == 50); 108 | 109 | // std::find. 110 | auto it = std::find(v.begin(), v.end(), 30); 111 | assert(it != v.end()); 112 | assert(*it == 30); 113 | assert(std::distance(v.begin(), it) == 2); 114 | 115 | PASS(); 116 | } 117 | 118 | void test_access_modifiers() 119 | { 120 | TEST("Access & Modifiers (Push, Pop, At)"); 121 | 122 | z_vec::vector points; 123 | 124 | // Push Back. 125 | points.push_back({1.0f, 2.0f}); 126 | points.push_back({3.0f, 4.0f}); 127 | 128 | assert(points.size() == 2); 129 | assert(points.back().y == 4.0f); 130 | 131 | // Bounds checking (at). 132 | try { 133 | auto val = points.at(100); 134 | (void)val; 135 | assert(false && "Should have thrown out_of_range"); 136 | } catch (const std::out_of_range& e) 137 | { 138 | // Success. 139 | } 140 | 141 | // Pop Back. 142 | points.pop_back(); 143 | assert(points.size() == 1); 144 | assert(points.back().x == 1.0f); 145 | 146 | // Clear. 147 | points.clear(); 148 | assert(points.empty()); 149 | assert(points.capacity() > 0); // Capacity retained 150 | 151 | PASS(); 152 | } 153 | 154 | // Ensure const-correctness works. 155 | void const_reader(const z_vec::vector& v) 156 | { 157 | assert(!v.empty()); 158 | assert(v[0] == 100); 159 | // v[0] = 5; // Should compile error if uncommented. 160 | } 161 | 162 | void test_const_correctness() 163 | { 164 | TEST("Const Correctness"); 165 | 166 | z_vec::vector v = {100}; 167 | const_reader(v); 168 | 169 | PASS(); 170 | } 171 | 172 | void test_complex_types() 173 | { 174 | TEST("Complex Types (std::string Safety)"); 175 | 176 | z_vec::vector vec; 177 | std::string s = "This string is long enough to force heap allocation, verifying memory safety."; 178 | 179 | // 1. Push element (construct/assign). 180 | vec.push_back(s); 181 | assert(vec.front() == s); 182 | 183 | // Force reallocation (reserve). 184 | vec.reserve(100); 185 | 186 | assert(vec.front() == s); 187 | assert(vec.capacity() >= 100); 188 | 189 | // Pop (destruct). 190 | vec.pop_back(); 191 | assert(vec.empty()); 192 | 193 | PASS(); 194 | } 195 | 196 | int main() 197 | { 198 | std::cout << "=> Running tests (zvec.h, cpp).\n"; 199 | 200 | test_constructors(); 201 | test_rule_of_five(); 202 | test_stl_interop(); 203 | test_access_modifiers(); 204 | test_const_correctness(); 205 | test_complex_types(); 206 | 207 | std::cout << "=> All tests passed successfully.\n"; 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /tests/test_main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct 7 | { 8 | float x, y; 9 | } Vec2; 10 | 11 | #define REGISTER_ZVEC_TYPES(X) \ 12 | X(int, Int) \ 13 | X(Vec2, Vec2) 14 | 15 | #include "zvec.h" 16 | 17 | #define TEST(name) printf("[TEST] %-35s", name); 18 | #define PASS() printf(" \033[0;32mPASS\033[0m\n") 19 | 20 | int cmp_int(const int *a, const int *b) 21 | { 22 | return *a - *b; 23 | } 24 | int cmp_vec2_x(const Vec2 *a, const Vec2 *b) 25 | { 26 | return (int)(a->x - b->x); 27 | } 28 | 29 | 30 | void test_init_management(void) 31 | { 32 | TEST("Init, From, Reserve, Shrink, Clear"); 33 | 34 | // zvec_init. 35 | zvec_Int v1 = zvec_init(Int); 36 | assert(zvec_is_empty(&v1)); 37 | assert(v1.capacity == 0); 38 | 39 | // zvec_init_with_cap. 40 | zvec_Int v2 = zvec_init_with_cap(Int, 50); 41 | assert(v2.length == 0); 42 | assert(v2.capacity == 50); // Exact reservation check. 43 | 44 | // zvec_from (Variadic init). 45 | zvec_Int v3 = zvec_from(Int, 10, 20, 30); 46 | assert(v3.length == 3); 47 | assert(*zvec_at(&v3, 0) == 10); 48 | assert(*zvec_at(&v3, 2) == 30); 49 | 50 | // zvec_reserve. 51 | zvec_reserve(&v1, 100); 52 | assert(v1.capacity >= 100); 53 | 54 | // zvec_clear. 55 | zvec_clear(&v3); 56 | assert(v3.length == 0); 57 | assert(v3.capacity > 0); // Capacity should remain. 58 | 59 | // zvec_shrink_to_fit. 60 | // Push one item, then shrink. Cap should equal len (1). 61 | zvec_push(&v3, 99); 62 | zvec_shrink_to_fit(&v3); 63 | assert(v3.capacity == 1); 64 | 65 | zvec_free(&v1); 66 | zvec_free(&v2); 67 | zvec_free(&v3); 68 | PASS(); 69 | } 70 | 71 | void test_data_access(void) 72 | { 73 | TEST("At, Last, Data, Is_Empty"); 74 | 75 | zvec_Int v = zvec_init(Int); 76 | assert(zvec_is_empty(&v) == 1); 77 | 78 | zvec_push(&v, 100); 79 | zvec_push(&v, 200); 80 | 81 | assert(zvec_is_empty(&v) == 0); 82 | 83 | // zvec_at (bounds check logic inside macro returns NULL). 84 | assert(*zvec_at(&v, 0) == 100); 85 | assert(zvec_at(&v, 999) == NULL); 86 | 87 | // zvec_last. 88 | assert(*zvec_last(&v) == 200); 89 | 90 | // zvec_data. 91 | int* raw = zvec_data(&v); 92 | assert(raw[0] == 100); 93 | assert(raw[1] == 200); 94 | 95 | zvec_free(&v); 96 | PASS(); 97 | } 98 | 99 | void test_modification(void) 100 | { 101 | TEST("Push, Slot, Pop, Extend, Remove"); 102 | 103 | zvec_Int v = zvec_init(Int); 104 | 105 | // zvec_push. 106 | zvec_push(&v, 1); 107 | zvec_push(&v, 2); 108 | zvec_push(&v, 3); // [1, 2, 3]. 109 | 110 | // zvec_pop. 111 | zvec_pop(&v); // [1, 2]. 112 | assert(v.length == 2); 113 | assert(*zvec_last(&v) == 2); 114 | 115 | // zvec_pop_get. 116 | int val = zvec_pop_get(&v); // Returns 2, list is [1]. 117 | assert(val == 2); 118 | assert(v.length == 1); 119 | 120 | // zvec_extend. 121 | int arr[] = {4, 5, 6}; 122 | zvec_extend(&v, arr, 3); // [1, 4, 5, 6]. 123 | assert(v.length == 4); 124 | assert(*zvec_last(&v) == 6); 125 | 126 | // zvec_remove (Preserves order). 127 | // Remove index 1 (value 4). Result: [1, 5, 6]. 128 | zvec_remove(&v, 1); 129 | assert(v.length == 3); 130 | assert(*zvec_at(&v, 0) == 1); 131 | assert(*zvec_at(&v, 1) == 5); 132 | assert(*zvec_at(&v, 2) == 6); 133 | 134 | // zvec_swap_remove (O(1), breaks order). 135 | // Remove index 0 (value 1). Swaps with last (6). Result: [6, 5]. 136 | zvec_swap_remove(&v, 0); 137 | assert(v.length == 2); 138 | assert(*zvec_at(&v, 0) == 6); 139 | assert(*zvec_at(&v, 1) == 5); 140 | 141 | // zvec_reverse. 142 | zvec_reverse(&v); // [5, 6]. 143 | assert(*zvec_at(&v, 0) == 5); 144 | 145 | // zvec_push_slot (Struct optimization). 146 | zvec_Vec2 points = zvec_init(Vec2); 147 | Vec2* p = zvec_push_slot(&points); // Reserves and returns ptr. 148 | p->x = 10.0f; 149 | p->y = 20.0f; 150 | assert(points.length == 1); 151 | assert(zvec_at(&points, 0)->x == 10.0f); 152 | 153 | zvec_free(&v); 154 | zvec_free(&points); 155 | PASS(); 156 | } 157 | 158 | void test_algorithms(void) 159 | { 160 | TEST("Sort, BSearch, LowerBound, Foreach"); 161 | 162 | zvec_Int v = zvec_from(Int, 50, 10, 30, 20, 40); 163 | 164 | // zvec_foreach. 165 | int sum = 0; 166 | zvec_foreach(&v, it) 167 | { 168 | sum += *it; 169 | } 170 | assert(sum == 150); 171 | 172 | // zvec_sort. 173 | zvec_sort(&v, cmp_int); // [10, 20, 30, 40, 50]. 174 | assert(*zvec_at(&v, 0) == 10); 175 | assert(*zvec_at(&v, 4) == 50); 176 | 177 | // zvec_bsearch. 178 | int key = 30; 179 | int* res = zvec_bsearch(&v, &key, cmp_int); 180 | assert(res != NULL && *res == 30); 181 | 182 | key = 99; 183 | res = zvec_bsearch(&v, &key, cmp_int); 184 | assert(res == NULL); 185 | 186 | // zvec_lower_bound. 187 | // List: [10, 20, 30, 40, 50]. 188 | // LB(25) should be 30 (index 2). 189 | key = 25; 190 | res = zvec_lower_bound(&v, &key, cmp_int); 191 | assert(res != NULL && *res == 30); 192 | 193 | // LB(5) should be 10 (index 0). 194 | key = 5; 195 | res = zvec_lower_bound(&v, &key, cmp_int); 196 | assert(res != NULL && *res == 10); 197 | 198 | // LB(60) should be NULL (end). 199 | key = 60; 200 | res = zvec_lower_bound(&v, &key, cmp_int); 201 | assert(res == NULL); 202 | 203 | zvec_free(&v); 204 | PASS(); 205 | } 206 | 207 | // Extension test (GCC/Clang only). 208 | #if defined(__GNUC__) || defined(__clang__) 209 | void test_autofree(void) 210 | { 211 | TEST("Auto-Cleanup Extension"); 212 | 213 | // We create a scope block to verify compilation and execution. 214 | // But verifying actual memory release requires Valgrind/ASAN. 215 | { 216 | zvec_autofree(Int) auto_v = zvec_init(Int); 217 | zvec_push(&auto_v, 123); 218 | assert(*zvec_at(&auto_v, 0) == 123); 219 | } // auto_v is freed here. 220 | 221 | PASS(); 222 | } 223 | #endif 224 | 225 | int main(void) 226 | { 227 | printf("=> Running tests (zvec.h, main).\n"); 228 | 229 | test_init_management(); 230 | test_data_access(); 231 | test_modification(); 232 | test_algorithms(); 233 | 234 | #if defined(__GNUC__) || defined(__clang__) 235 | test_autofree(); 236 | #endif 237 | 238 | printf("=> All tests passed successfully.\n"); 239 | return 0; 240 | } 241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zvec.h 2 | 3 | `zvec.h` provides dynamic arrays (vectors) for C projects. Unlike typical C vector implementations that rely on `void*` casting and lose type safety, `zvec.h` uses C11 `_Generic` selection and X-Macros to generate fully typed, type-safe implementations for your specific data structures. 4 | 5 | It also includes a robust **C++11 wrapper**, allowing you to use it as a lightweight, drop-in vector class (`z_vec::vector`) in mixed codebases while sharing the same underlying C implementation. 6 | 7 | It is part of the [zdk](https://github.com/z-libs/zdk) suite. 8 | 9 | ## Features 10 | 11 | * **Type Safety**: Compiler errors if you try to push a `float` into a `vec_int`. 12 | * **Native Performance**: Data is stored in contiguous arrays of the actual type (no boxing or pointer indirection). 13 | * **C++ Support**: Includes a full C++ class wrapper with RAII, iterators, and `std::vector`-like API. 14 | * **Zero Boilerplate**: Use the **Z-Scanner** tool to automatically generate type registrations. 15 | * **Header Only**: No linking required. 16 | * **Memory Agnostic**: Supports custom allocators (Arenas, Pools, Debuggers). 17 | * **Zero Dependencies**: Only standard C headers used. 18 | 19 | ## Installation 20 | 21 | ### Manual 22 | 23 | `zvec.h` works best when you use the provided scanner script to manage type registrations, though it can be used manually. 24 | 25 | 1. Copy `zvec.h` (and `zcommon.h` if separated) to your project's include folder. 26 | 2. Add the `z-core` tools (optional but recommended): 27 | 28 | ```bash 29 | git submodule add https://github.com/z-libs/z-core.git z-core 30 | ``` 31 | 32 | ### Clib 33 | 34 | If you use the clib package manager, run: 35 | 36 | ```bash 37 | clib install z-libs/zdk 38 | ``` 39 | 40 | ### ZDK (Recommended) 41 | 42 | If you use the Zen Development Kit, it is included automatically by including `` (or ``). 43 | 44 | ## Usage: C 45 | 46 | For C projects, you define the vector types you need using a macro that the scanner detects. 47 | 48 | ```c 49 | #include 50 | #include "zvec.h" 51 | 52 | // Define your struct. 53 | typedef struct { float x, y; } Point; 54 | 55 | // Request the vector types you need. 56 | // (These are no-ops for the compiler, but markers for the scanner). 57 | DEFINE_VEC_TYPE(int, Int) 58 | DEFINE_VEC_TYPE(Point, Point) 59 | 60 | int main(void) 61 | { 62 | // Initialize (Standard C style). 63 | zvec_Int nums = zvec_init(Int); 64 | zvec_push(&nums, 42); 65 | 66 | // Initialize Struct Vector. 67 | zvec_Point path = zvec_init(Point); 68 | zvec_push(&path, ((Point){1.0f, 2.0f})); 69 | 70 | // Access elements safely (returns T*). 71 | printf("First number: %d\n", *zvec_at(&nums, 0)); 72 | 73 | // Cleanup. 74 | zvec_free(&nums); 75 | zvec_free(&path); 76 | return 0; 77 | } 78 | ``` 79 | 80 | ## Usage: C++ 81 | 82 | The library detects C++ compilers automatically. The C++ wrapper lives in the **`z_vec`** namespace and wraps the underlying C implementation transparently. 83 | 84 | ```cpp 85 | #include 86 | #include "zvec.h" 87 | 88 | struct Point { float x, y; }; 89 | 90 | // Request types (scanner sees this even in .cpp files). 91 | DEFINE_VEC_TYPE(int, Int) 92 | DEFINE_VEC_TYPE(Point, Point) 93 | 94 | int main() 95 | { 96 | // RAII handles memory automatically. 97 | z_vec::vector nums = {1, 2, 3}; 98 | 99 | // Standard push_back API. 100 | nums.push_back(42); 101 | 102 | // Range-based for loops supported. 103 | for(int n : nums) { 104 | std::cout << n << " "; 105 | } 106 | 107 | // Bounds checking access. 108 | try { 109 | nums.at(99) = 10; 110 | } catch (const std::out_of_range& e) { 111 | std::cerr << "Error: " << e.what() << "\n"; 112 | } 113 | 114 | return 0; 115 | } 116 | ``` 117 | 118 | ## Compilation Guide 119 | 120 | Since `zvec.h` relies on code generation for its type safety, here you have the guide if you use the scanner. 121 | 122 | **[Read the Compilation Guide](examples/README.md)** for detailed instructions on how to use `zscanner.py`. 123 | 124 | ## Manual Setup 125 | 126 | If you cannot use Python or prefer manual control, you can use the **Registry Header** approach. 127 | 128 | * Create a file named `my_vectors.h` (or something else). 129 | * Register your types using X-Macros. 130 | 131 | ```c 132 | #ifndef MY_VECTORS_H 133 | #define MY_VECTORS_H 134 | 135 | #define REGISTER_ZVEC_TYPES(X) \ 136 | X(int, Int) \ 137 | X(float, Float) 138 | 139 | // **IT HAS TO BE INCLUDED AFTER, NOT BEFORE**. 140 | #include "zvec.h" 141 | 142 | #endif 143 | ``` 144 | 145 | * Include `"my_vectors.h"` instead of `"zvec.h"` in your C files. 146 | 147 | ## API Reference (C) 148 | 149 | `zvec.h` uses C11 `_Generic` to automatically select the correct function implementation based on the vector type you pass. 150 | 151 | **Initialization & Management** 152 | 153 | | Macro | Description | 154 | | :--- | :--- | 155 | | `zvec_init(Type)` | Returns an empty vector structure initialized to zero. | 156 | | `zvec_init_with_cap(Type, n)` | Returns a vector with initial memory reserved for `n` elements. | 157 | | `zvec_from(Type, ...)` | Returns a vector populated with the provided elements (for example, `zvec_from(int, 1, 2, 3)`). | 158 | | `zvec_free(v)` | Frees the internal memory array and zeroes the vector structure. | 159 | | `zvec_clear(v)` | Sets the length to 0 but keeps the allocated memory capacity. | 160 | | `zvec_reserve(v, n)` | Ensures the vector has capacity for at least `n` elements total. | 161 | | `zvec_shrink_to_fit(v)` | Reallocates the internal memory to match exactly the current length. | 162 | 163 | **Data Access** 164 | 165 | | Macro | Description | 166 | | :--- | :--- | 167 | | `zvec_at(v, index)` | Returns a **pointer** to the element at `index`, or `NULL` if out of bounds. | 168 | | `zvec_last(v)` | Returns a **pointer** to the last element in the vector. | 169 | | `zvec_data(v)` | Returns the raw underlying array pointer (`T*`). | 170 | | `zvec_is_empty(v)` | Returns `1` (true) if the vector length is 0, otherwise `0`. | 171 | 172 | **Modification** 173 | 174 | | Macro | Description | 175 | | :--- | :--- | 176 | | `zvec_push(v, value)` | Appends value to the end. Copies data twice (stack -> heap). Best for simple types. | 177 | | `zvec_push_slot(v, value)` | Reserves space at the end and returns a **pointer** to it. Zero overhead. Best for large structs. | 178 | | `zvec_pop(v)` | Removes the last element. Decrements length. | 179 | | `zvec_pop_get(v)` | Removes the last element and **returns** its value. | 180 | | `zvec_extend(v, arr, count)` | Appends `count` elements from the raw array `arr` to the end of the vector. | 181 | | `zvec_remove(v, index)` | Removes the element at `index`, shifting all subsequent elements left (preserves order). | 182 | | `zvec_swap_remove(v, index)` | Removes the element at `index` by swapping it with the last element (O(1), order not preserved). | 183 | | `zvec_reverse(v)` | Reverses the elements of the vector in-place. | 184 | 185 | **Algorithms & Iteration** 186 | 187 | | Macro | Description | 188 | | :--- | :--- | 189 | | `zvec_foreach(v, it)` | Standard traversal. **GCC/Clang**: Auto-declares `it`. **Std C**: `it` must be declared before loop. | 190 | | `zvec_foreach_decl(Name, v, it)` | **Portable C99**. Iterates and declares `it` as a pointer inside the loop. Requires type Name. | 191 | | `zvec_sort(v, cmp)` | Sorts the vector in-place using standard `qsort`. `cmp` is a function pointer: `int (*)(const T*, const T*)`. | 192 | | `zvec_bsearch(v, key, cmp)` | Performs a binary search. Returns a pointer to the found element or `NULL`. `key` is `const T*`. | 193 | | `zvec_lower_bound(v, key, cmp)`| Returns a pointer to the first element that does not compare less than `key`. Returns `NULL` if all elements are smaller. | 194 | 195 | **Extensions (Experimental)** 196 | 197 | If you are using a compiler that supports `__attribute__((cleanup))` (like GCC or Clang), you can use the **Auto-Cleanup** extension to automatically free vectors when they go out of scope. 198 | 199 | | Macro | Description | 200 | | :--- | :--- | 201 | | `zvec_autofree(Type)` | Declares a vector that automatically calls `zvec_free` when the variable leaves scope (RAII style). | 202 | 203 | **Example:** 204 | ```c 205 | void process_data() 206 | { 207 | // 'nums' will be automatically freed when this function returns. 208 | zvec_autofree(int) nums = zvec_init(int); 209 | zvec_push(&nums, 100); 210 | } 211 | ``` 212 | 213 | > **Disable Extensions:** To force standard compliance and disable these extensions, define `Z_NO_EXTENSIONS` before including the library. 214 | 215 | ### Safe API (Error Handling) 216 | 217 | If your project includes **[`zerror.h`](https://github.com/z-libs/zerror.h)**, `zvec.h` automatically exposes a "Safe Mode" API. 218 | 219 | Unlike the standard API (which asserts or returns `NULL` on failure), the Safe API returns **Result Objects** (`zres` or `Res_Type`). These results contain full stack traces and debug information if an error occurs (for example, Out of Memory, Index Out of Bounds). 220 | 221 | > **Note:** To use the short macros (`try`, `check`, `unwrap`), you must define `#define Z_SHORT_ERR` before including the headers. 222 | 223 | **Safe Macros** 224 | 225 | | Macro | Returns | Description | 226 | | :--- | :--- | :--- | 227 | | `zvec_push_safe(v, val)` | `zres` | Appends a value. Returns an error if memory allocation fails (OOM). | 228 | | `zvec_reserve_safe(v, n)` | `zres` | Reserves capacity. Returns an error if memory allocation fails. | 229 | | `zvec_at_safe(v, index)` | `Res_Type` | Returns the value at `index`. Returns an error if the index is out of bounds. | 230 | | `zvec_pop_safe(v)` | `Res_Type` | Removes and returns the last element. Returns an error if the vector is empty. | 231 | | `zvec_last_safe(v)` | `Res_Type` | Returns the last element (without removing). Returns an error if empty. | 232 | 233 | **Example Usage** 234 | 235 | The Safe API is designed to work with `zerror`'s flow control macros. 236 | 237 | ```c 238 | #define ZERROR_IMPLEMENTATION 239 | #define ZERROR_SHORT_NAMES 240 | #include "zvec.h" 241 | #include "zerror.h" 242 | 243 | DEFINE_VEC_TYPE(int, Int) 244 | 245 | zres process_data() 246 | { 247 | zvec_autofree(Int) nums = zvec_init(Int); 248 | 249 | // -> Check for OOM on push. 250 | // We use check_ctx to add context to the error if it fails. 251 | check_ctx(zvec_push_safe(&nums, 100), "Failed to push first item"); 252 | check_ctx(zvec_push_safe(&nums, 200), "Failed to push second item"); 253 | 254 | // -> Safe Access (Bounds Checking). 255 | // We use try_into() because vec_at_safe returns 'Res_Int', 256 | // but this function must return 'zres' on failure. 257 | int val = try_into(zres, zvec_at_safe(&nums, 1)); 258 | 259 | printf("Value is: %d\n", val); 260 | 261 | // -> Panic on failure (Crash with stack trace). 262 | // Useful if you are 100% sure the index exists. 263 | int must_exist = unwrap(zvec_at_safe(&nums, 0)); 264 | 265 | return zres_ok(); 266 | } 267 | 268 | int main(void) 269 | { 270 | // If process_data fails, it prints a full error log. 271 | run(process_data()); 272 | return 0; 273 | } 274 | ``` 275 | 276 | ## API Reference (C++) 277 | 278 | The C++ wrapper lives in the **`z_vec`** namespace. It strictly adheres to RAII principles and delegates all logic to the underlying C implementation. 279 | 280 | ### `class z_vec::vector` 281 | 282 | **Constructors & Management** 283 | 284 | | Method | Description | 285 | | :--- | :--- | 286 | | `vector()` | Default constructor (empty). | 287 | | `vector(size_t cap)` | Constructs with initial capacity reserved. | 288 | | `vector({1, 2, ...})` | Constructs from an initializer list. | 289 | | `~vector()` | Destructor. Automatically calls `vec_free`. | 290 | | `operator=` | Copy and Move assignment operators. | 291 | 292 | **Access & Iterators** 293 | 294 | | Method | Description | 295 | | :--- | :--- | 296 | | `data()` | Returns `T*` (mutable) or `const T*`. | 297 | | `size()` | Returns current number of elements. | 298 | | `capacity()` | Returns current allocated capacity. | 299 | | `empty()` | Returns `true` if size is 0. | 300 | | `operator[]` | Unchecked access to element at index. | 301 | | `at(index)` | Bounds-checked access. Throws `std::out_of_range`. | 302 | | `front()`, `back()` | Access first/last element. | 303 | | `begin()`, `end()` | Standard iterators (pointers) compatible with STL algorithms. | 304 | 305 | **Modification** 306 | 307 | | Method | Description | 308 | | :--- | :--- | 309 | | `push_back(val)` | Appends value to the end. | 310 | | `pop_back()` | Removes the last element. | 311 | | `reserve(n)` | Reserves capacity for at least `n` items. | 312 | | `clear()` | Sets size to 0 (capacity remains). | 313 | | `shrink_to_fit()` | Reduces capacity to match size. | 314 | | `reverse()` | Reverses elements in-place. | 315 | | `remove(index)` | Removes element at index (O(N) shift). | 316 | | `swap_remove(index)` | Removes element at index by swapping with last (O(1)). | 317 | 318 | ## Memory Management 319 | 320 | By default, `zvec.h` uses the standard C library functions (`malloc`, `calloc`, `realloc`, `free`). 321 | 322 | However, you can override these to use your own memory subsystem (e.g., **Memory Arenas**, **Pools**, or **Debug Allocators**). 323 | 324 | ### First Option: Global Override (Recommended) 325 | 326 | To use a custom allocator, define the `Z_` macros **inside your registry header**, immediately before including `zvec.h`. 327 | 328 | **Example: my_vectors.h** 329 | 330 | ```c 331 | #ifndef MY_VECTORS_H 332 | #define MY_VECTORS_H 333 | 334 | // Define your custom memory macros **HERE**. 335 | #include "my_memory_system.h" 336 | 337 | // IMPORTANT: Override all four to prevent mixing allocators. 338 | // This applies to all the z-libs. 339 | #define Z_MALLOC(sz) my_custom_alloc(sz) 340 | #define Z_CALLOC(n, sz) my_custom_calloc(n, sz) 341 | #define Z_REALLOC(p, sz) my_custom_realloc(p, sz) 342 | #define Z_FREE(p) my_custom_free(p) 343 | 344 | 345 | // Then include the library. 346 | #include "zvec.h" 347 | 348 | // ... Register types ... 349 | 350 | 351 | #endif 352 | ``` 353 | 354 | > **Note:** You **must** override **all four macros** (`MALLOC`, `CALLOC`, `REALLOC`, `FREE`) if you override one, to ensure consistency. 355 | 356 | ### Second Option: Library-Specific Override (Advanced) 357 | 358 | If you need different allocators for different containers (e.g., an Arena for Lists but the Heap for Vectors), you can use the library-specific macros. These take priority over the global `Z_` macros. 359 | 360 | ```c 361 | // Example: Vectors use a Frame Arena, everything else uses standard malloc. 362 | #define ZVEC_CALLOC(n, sz) arena_alloc_zero(frame_arena, (n) * (sz)) 363 | #define ZVEC_REALLOC(p, sz) arena_resize(frame_arena, p, sz) 364 | #define ZVEC_FREE(p) /* no-op for linear arena */ 365 | // (ZVEC_MALLOC is strictly unused by zvec internally, but good to define for consistency). 366 | 367 | #include "zvec.h" 368 | #include "zlist.h" // zlist will still use standard malloc! 369 | ``` 370 | 371 | ## Short Names (Opt-In) 372 | 373 | If you prefer a cleaner API and don't have naming conflicts, define `ZVEC_SHORT_NAMES` before including the header. This allows you to use aliases like `vec_push` and `vec_free` instead of their prefixed counterparts. 374 | 375 | 376 | ## Notes 377 | 378 | ### Why do I need to provide a "Short Name"? 379 | 380 | In `REGISTER_TYPES(X)`, you must provide two arguments: the **Actual Type** and a **Short Name**. 381 | 382 | ```c 383 | // Actual Type Short Name 384 | X(unsigned long, ulong) 385 | ``` 386 | 387 | The reason is that C macros cannot handle spaces when generating names. The library tries to create functions by gluing `zvec_` + `Name`. 388 | 389 | If you used `unsigned long` as the name, the macro would try to generate `vec_unsigned long`, which is a syntax error (variable names cannot contain spaces). But, by passing `ulong`, it correctly generates `vec_ulong`. 390 | -------------------------------------------------------------------------------- /src/zvec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * zvec.h — Type-safe, zero-overhead dynamic arrays 3 | * Part of Zen Development Kit (ZDK) 4 | * 5 | * This is a macro-generated, single-header dynamic array library that produces 6 | * fully type-safe vector implementations at compile time. It supports both C and C++ 7 | * with zero-cost abstraction. 8 | * 9 | * Features: 10 | * • C11 _Generic interface (zvec_push(v, x)) 11 | * • Full RAII C++ wrapper in namespace z_vec::vector 12 | * • Fast path (asserts + int error codes) and safe path (zres) 13 | * • Optional short names via ZVEC_SHORT_NAMES 14 | * • Automatic type registration via z_registry.h or manual DEFINE_ macros 15 | * 16 | * License: MIT 17 | * Author: Zuhaitz 18 | * Repository: https://github.com/z-libs/zvec.h 19 | * Version: 1.0.3 20 | */ 21 | 22 | #ifndef ZVEC_H 23 | #define ZVEC_H 24 | 25 | #include "zcommon.h" 26 | #include 27 | #include 28 | #include 29 | 30 | #if defined(__has_include) && __has_include("zerror.h") 31 | # include "zerror.h" 32 | # define Z_HAS_ZERROR 1 33 | #elif defined(ZERROR_H) 34 | # define Z_HAS_ZERROR 1 35 | #else 36 | # define Z_HAS_ZERROR 0 37 | #endif 38 | 39 | // C++ interop preamble. 40 | #ifdef __cplusplus 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | namespace z_vec 49 | { 50 | // Traits struct - connects C++ wrapper to generated C functions. 51 | template 52 | struct traits 53 | { 54 | static_assert(0 == sizeof(T), "No zvec implementation registered for this type. " 55 | "Use REGISTER_ZVEC_TYPES() or Z_AUTOGEN_VECS() before including zvec.h."); 56 | }; 57 | 58 | // C++ RAII vector wrapper. 59 | template 60 | class vector 61 | { 62 | using Traits = traits; 63 | using CType = typename Traits::c_type; 64 | 65 | CType inner; 66 | 67 | public: 68 | using value_type = T; 69 | using size_type = size_t; 70 | using difference_type = std::ptrdiff_t; 71 | using pointer = T *; 72 | using const_pointer = const T *; 73 | using iterator = T *; 74 | using const_iterator = const T *; 75 | 76 | // Constructors and destructor (RAII). 77 | 78 | vector() 79 | { 80 | Traits::init(inner); 81 | } 82 | 83 | explicit vector(size_t capacity) 84 | { 85 | Traits::init_cap(inner, capacity); 86 | } 87 | 88 | vector(std::initializer_list init) 89 | { 90 | Traits::init_cap(inner, init.size()); 91 | Traits::extend(inner, init.begin(), init.size()); 92 | } 93 | 94 | vector(const vector &other) 95 | { 96 | Traits::init_cap(inner, other.size()); 97 | Traits::extend(inner, other.data(), other.size()); 98 | } 99 | 100 | vector(vector &&other) noexcept 101 | { 102 | inner = other.inner; 103 | Traits::init(other.inner); 104 | } 105 | 106 | ~vector() 107 | { 108 | Traits::free(inner); 109 | } 110 | 111 | vector &operator=(const vector &other) 112 | { 113 | if (&other != this) 114 | { 115 | Traits::free(inner); 116 | Traits::init_cap(inner, other.size()); 117 | Traits::extend(inner, other.data(), other.size()); 118 | } 119 | return *this; 120 | } 121 | 122 | vector &operator=(vector &&other) noexcept 123 | { 124 | if (&other != this) 125 | { 126 | Traits::free(inner); 127 | inner = other.inner; 128 | Traits::init(other.inner); 129 | } 130 | return *this; 131 | } 132 | 133 | // Accessors. 134 | 135 | T *data() 136 | { 137 | return inner.data; 138 | } 139 | 140 | const T *data() const 141 | { 142 | return inner.data; 143 | } 144 | 145 | size_t size() const 146 | { 147 | return inner.length; 148 | } 149 | 150 | size_t capacity() const 151 | { 152 | return inner.capacity; 153 | } 154 | 155 | bool empty() const 156 | { 157 | return 0 == inner.length; 158 | } 159 | 160 | T &operator[](size_t idx) 161 | { 162 | return inner.data[idx]; 163 | } 164 | 165 | const T &operator[](size_t idx) const 166 | { 167 | return inner.data[idx]; 168 | } 169 | 170 | T &at(size_t idx) 171 | { 172 | if (idx >= size()) 173 | { 174 | throw std::out_of_range("vector::at"); 175 | } 176 | return inner.data[idx]; 177 | } 178 | 179 | const T &at(size_t idx) const 180 | { 181 | if (idx >= size()) throw std::out_of_range("vector::at"); 182 | return inner.data[idx]; 183 | } 184 | 185 | T &front() 186 | { 187 | return inner.data[0]; 188 | } 189 | 190 | const T &front() const 191 | { 192 | return inner.data[0]; 193 | } 194 | 195 | T &back() 196 | { 197 | return inner.data[inner.length - 1]; 198 | } 199 | 200 | const T &back() const 201 | { 202 | return inner.data[inner.length - 1]; 203 | } 204 | 205 | // Modifiers. 206 | 207 | void push_back(const T &val) 208 | { 209 | if (Z_OK != Traits::push(inner, val)) 210 | { 211 | throw std::bad_alloc(); 212 | } 213 | } 214 | 215 | void pop_back() 216 | { 217 | Traits::pop(inner); 218 | } 219 | 220 | void clear() 221 | { 222 | Traits::clear(inner); 223 | } 224 | 225 | void reserve(size_t cap) 226 | { 227 | if (Z_OK != Traits::reserve(inner, cap)) 228 | { 229 | throw std::bad_alloc(); 230 | } 231 | } 232 | 233 | void shrink_to_fit() 234 | { 235 | Traits::shrink(inner); 236 | } 237 | 238 | void reverse() 239 | { 240 | Traits::reverse(inner); 241 | } 242 | 243 | void remove(size_t idx) 244 | { 245 | Traits::remove(inner, idx); 246 | } 247 | 248 | void swap_remove(size_t idx) 249 | { 250 | Traits::swap_remove(inner, idx); 251 | } 252 | 253 | // Iterators. 254 | 255 | iterator begin() 256 | { 257 | return inner.data; 258 | } 259 | 260 | iterator end() 261 | { 262 | return inner.data + inner.length; 263 | } 264 | 265 | const_iterator begin() const 266 | { 267 | return inner.data; 268 | } 269 | 270 | const_iterator end() const 271 | { 272 | return inner.data + inner.length; 273 | } 274 | }; 275 | } 276 | 277 | extern "C" { 278 | #endif 279 | 280 | // Allocator overrides (user may redefine). 281 | #ifndef ZVEC_MALLOC 282 | #define ZVEC_MALLOC(sz) Z_MALLOC(sz) 283 | #endif 284 | 285 | #ifndef ZVEC_CALLOC 286 | #define ZVEC_CALLOC(n, sz) Z_CALLOC(n, sz) 287 | #endif 288 | 289 | #ifndef ZVEC_REALLOC 290 | #define ZVEC_REALLOC(p, sz) Z_REALLOC(p, sz) 291 | #endif 292 | 293 | #ifndef ZVEC_FREE 294 | #define ZVEC_FREE(p) Z_FREE(p) 295 | #endif 296 | 297 | /* 298 | * Safe API generation (requires zerror.h). 299 | * 300 | * When Z_HAS_ZERROR is true, each generated vector type gets safe variants. 301 | * * MODIFIED: Disabled for C++ to prevent errors with unions containing classes. 302 | */ 303 | #if Z_HAS_ZERROR && !defined(__cplusplus) 304 | 305 | static inline zerr zvec_err_impl(int code, const char *msg, 306 | const char *file, int line, const char *func) 307 | { 308 | return zerr_create_impl(code, file, line, func, "%s", msg); 309 | } 310 | 311 | #define ZVEC_GEN_SAFE_IMPL(T, Name) \ 312 | DEFINE_RESULT(T, Res_##Name) \ 313 | \ 314 | static inline zres zvec_push_safe_##Name(zvec_##Name *v, T value, \ 315 | const char *f, int l, const char *fn) \ 316 | { \ 317 | if (v->length >= v->capacity) \ 318 | { \ 319 | size_t new_cap = Z_GROWTH_FACTOR(v->capacity); \ 320 | T *new_data = (T *)ZVEC_REALLOC(v->data, new_cap * sizeof(T)); \ 321 | if (!new_data) \ 322 | { \ 323 | return zres_err(zvec_err_impl(Z_ENOMEM, "Vector Push OOM", f, l, fn)); \ 324 | } \ 325 | v->data = new_data; \ 326 | v->capacity = new_cap; \ 327 | } \ 328 | v->data[v->length++] = value; \ 329 | return zres_ok(); \ 330 | } \ 331 | \ 332 | static inline zres zvec_reserve_safe_##Name(zvec_##Name *v, size_t cap, \ 333 | const char *f, int l, const char *fn) \ 334 | { \ 335 | if (cap <= v->capacity) \ 336 | { \ 337 | return zres_ok(); \ 338 | } \ 339 | T *new_data = (T *)ZVEC_REALLOC(v->data, cap * sizeof(T)); \ 340 | if (!new_data) \ 341 | { \ 342 | return zres_err(zvec_err_impl(Z_ENOMEM, "Vector Reserve OOM", f, l, fn)); \ 343 | } \ 344 | v->data = new_data; \ 345 | v->capacity = cap; \ 346 | return zres_ok(); \ 347 | } \ 348 | \ 349 | static inline Res_##Name zvec_pop_safe_##Name(zvec_##Name *v, \ 350 | const char *f, int l, const char *fn) \ 351 | { \ 352 | if (0 == v->length) \ 353 | { \ 354 | return Res_##Name##_err(zvec_err_impl(Z_EEMPTY, "Pop empty vec", f, l, fn)); \ 355 | } \ 356 | return Res_##Name##_ok(v->data[--v->length]); \ 357 | } \ 358 | \ 359 | static inline Res_##Name zvec_at_safe_##Name(zvec_##Name *v, size_t i, \ 360 | const char *f, int l, const char *fn) \ 361 | { \ 362 | if (i >= v->length) \ 363 | { \ 364 | return Res_##Name##_err(zvec_err_impl(Z_EOOB, "Index out of bounds", f, l, fn));\ 365 | } \ 366 | return Res_##Name##_ok(v->data[i]); \ 367 | } \ 368 | \ 369 | static inline Res_##Name zvec_last_safe_##Name(zvec_##Name *v, \ 370 | const char *f, int l, const char *fn) \ 371 | { \ 372 | if (0 == v->length) \ 373 | { \ 374 | return Res_##Name##_err(zvec_err_impl(Z_EEMPTY, "Vector is empty", f, l, fn)); \ 375 | } \ 376 | return Res_##Name##_ok(v->data[v->length - 1]); \ 377 | } 378 | 379 | #else 380 | # define ZVEC_GEN_SAFE_IMPL(T, Name) 381 | #endif 382 | 383 | // C++ compatibility layers. 384 | 385 | #ifdef __cplusplus 386 | # define ZVEC_IMPL_ALLOC(T, Name) \ 387 | static inline int zvec_reserve_##Name(zvec_##Name *v, size_t new_cap) \ 388 | { \ 389 | if (new_cap <= v->capacity) \ 390 | { \ 391 | return Z_OK; \ 392 | } \ 393 | try { \ 394 | T* new_data = new T[new_cap]; \ 395 | for (size_t i = 0; i < v->length; ++i) \ 396 | { \ 397 | new_data[i] = std::move(v->data[i]); \ 398 | } \ 399 | if (v->data) \ 400 | { \ 401 | delete[] v->data; \ 402 | } \ 403 | v->data = new_data; \ 404 | v->capacity = new_cap; \ 405 | } catch (...) { return Z_ENOMEM; } \ 406 | return Z_OK; \ 407 | } \ 408 | \ 409 | static inline void zvec_free_##Name(zvec_##Name *v) \ 410 | { \ 411 | if (v->data) \ 412 | { \ 413 | delete[] v->data; \ 414 | } \ 415 | v->data = NULL; \ 416 | v->length = 0; \ 417 | v->capacity = 0; \ 418 | } \ 419 | \ 420 | static inline void zvec_remove_##Name(zvec_##Name *v, size_t index) \ 421 | { \ 422 | if (index >= v->length) \ 423 | { \ 424 | return; \ 425 | } \ 426 | for (size_t i = index; i < v->length - 1; ++i) \ 427 | { \ 428 | v->data[i] = std::move(v->data[i + 1]); \ 429 | } \ 430 | v->data[v->length - 1] = T(); \ 431 | v->length--; \ 432 | } \ 433 | \ 434 | static inline void zvec_shrink_to_fit_##Name(zvec_##Name *v) \ 435 | { \ 436 | if (v->length == v->capacity) \ 437 | { \ 438 | return; \ 439 | } \ 440 | if (0 == v->length) \ 441 | { \ 442 | zvec_free_##Name(v); \ 443 | return; \ 444 | } \ 445 | try \ 446 | { \ 447 | T* new_data = new T[v->length]; \ 448 | for (size_t i = 0; i < v->length; ++i) \ 449 | { \ 450 | new_data[i] = std::move(v->data[i]); \ 451 | } \ 452 | if (v->data) delete[] v->data; \ 453 | v->data = new_data; \ 454 | v->capacity = v->length; \ 455 | } \ 456 | catch (...) {} \ 457 | } 458 | 459 | // C++ dispatch: generates inline overloads so C++ can find functions without _Generic. 460 | # define ZVEC_CPP_DISPATCH_IMPL(T, Name) \ 461 | static inline int zvec_reserve_dispatch(zvec_##Name *v, size_t n) \ 462 | { \ 463 | return zvec_reserve_##Name(v, n); \ 464 | } \ 465 | \ 466 | static inline int zvec_push_dispatch(zvec_##Name *v, T val) \ 467 | { \ 468 | return zvec_push_##Name(v, val); \ 469 | } \ 470 | \ 471 | static inline T* zvec_push_slot_dispatch(zvec_##Name *v) \ 472 | { \ 473 | return zvec_push_slot_##Name(v); \ 474 | } \ 475 | \ 476 | static inline int zvec_extend_dispatch(zvec_##Name *v, const T *arr, size_t n) \ 477 | { \ 478 | return zvec_extend_##Name(v, arr, n); \ 479 | } \ 480 | \ 481 | static inline int zvec_is_empty_dispatch(zvec_##Name *v) \ 482 | { \ 483 | return zvec_is_empty_##Name(v); \ 484 | } \ 485 | \ 486 | static inline T* zvec_at_dispatch(zvec_##Name *v, size_t i) \ 487 | { \ 488 | return zvec_at_##Name(v, i); \ 489 | } \ 490 | \ 491 | static inline T* zvec_data_dispatch(zvec_##Name *v) \ 492 | { \ 493 | return zvec_data_##Name(v); \ 494 | } \ 495 | \ 496 | static inline T* zvec_last_dispatch(zvec_##Name *v) \ 497 | { \ 498 | return zvec_last_##Name(v); \ 499 | } \ 500 | \ 501 | static inline void zvec_free_dispatch(zvec_##Name *v) \ 502 | { \ 503 | zvec_free_##Name(v); \ 504 | } \ 505 | \ 506 | static inline void zvec_pop_dispatch(zvec_##Name *v) \ 507 | { \ 508 | zvec_pop_##Name(v); \ 509 | } \ 510 | \ 511 | static inline T zvec_pop_get_dispatch(zvec_##Name *v) \ 512 | { \ 513 | return zvec_pop_get_##Name(v); \ 514 | } \ 515 | \ 516 | static inline void zvec_shrink_to_fit_dispatch(zvec_##Name *v) \ 517 | { \ 518 | zvec_shrink_to_fit_##Name(v); \ 519 | } \ 520 | \ 521 | static inline void zvec_remove_dispatch(zvec_##Name *v, size_t i) \ 522 | { \ 523 | zvec_remove_##Name(v, i); \ 524 | } \ 525 | \ 526 | static inline void zvec_swap_remove_dispatch(zvec_##Name *v, size_t i) \ 527 | { \ 528 | zvec_swap_remove_##Name(v, i); \ 529 | } \ 530 | \ 531 | static inline void zvec_clear_dispatch(zvec_##Name *v) \ 532 | { \ 533 | zvec_clear_##Name(v); \ 534 | } \ 535 | \ 536 | static inline void zvec_reverse_dispatch(zvec_##Name *v) \ 537 | { \ 538 | zvec_reverse_##Name(v); \ 539 | } \ 540 | \ 541 | static inline void zvec_sort_dispatch(zvec_##Name *v, \ 542 | int (*cmp)(const T*, const T*)) \ 543 | { \ 544 | zvec_sort_##Name(v, cmp); \ 545 | } \ 546 | \ 547 | static inline T* zvec_bsearch_dispatch(zvec_##Name *v, const T* k, \ 548 | int (*cmp)(const T*, const T*)) \ 549 | { \ 550 | return zvec_bsearch_##Name(v, k, cmp); \ 551 | } \ 552 | \ 553 | static inline T* zvec_lower_bound_dispatch(zvec_##Name *v, const T* k, \ 554 | int (*cmp)(const T*, const T*)) \ 555 | { \ 556 | return zvec_lower_bound_##Name(v, k, cmp); \ 557 | } 558 | #else 559 | // C implementation: uses realloc / memmove / free. 560 | #define ZVEC_IMPL_ALLOC(T, Name) \ 561 | static inline int zvec_reserve_##Name(zvec_##Name *v, size_t new_cap) \ 562 | { \ 563 | if (new_cap <= v->capacity) \ 564 | { \ 565 | return Z_OK; \ 566 | } \ 567 | T* new_data = (T*)ZVEC_REALLOC(v->data, new_cap * sizeof(T)); \ 568 | if (!new_data) \ 569 | { \ 570 | return Z_ENOMEM; \ 571 | } \ 572 | v->data = new_data; \ 573 | v->capacity = new_cap; \ 574 | return Z_OK; \ 575 | } \ 576 | \ 577 | static inline void zvec_free_##Name(zvec_##Name *v) \ 578 | { \ 579 | ZVEC_FREE(v->data); \ 580 | memset(v, 0, sizeof(zvec_##Name)); \ 581 | } \ 582 | \ 583 | static inline void zvec_remove_##Name(zvec_##Name *v, size_t index) \ 584 | { \ 585 | if (index >= v->length) \ 586 | { \ 587 | return; \ 588 | } \ 589 | memmove(&v->data[index], &v->data[index + 1], (v->length - index - 1) * sizeof(T)); \ 590 | v->length--; \ 591 | } \ 592 | \ 593 | static inline void zvec_shrink_to_fit_##Name(zvec_##Name *v) \ 594 | { \ 595 | if (v->length == v->capacity) \ 596 | { \ 597 | return; \ 598 | } \ 599 | if (0 == v->length) \ 600 | { \ 601 | zvec_free_##Name(v); \ 602 | return; \ 603 | } \ 604 | T* new_data = (T*)ZVEC_REALLOC(v->data, v->length * sizeof(T)); \ 605 | if (new_data) \ 606 | { \ 607 | v->data = new_data; \ 608 | v->capacity = v->length; \ 609 | } \ 610 | } 611 | 612 | # define ZVEC_CPP_DISPATCH_IMPL(T, Name) // Empty in C. 613 | #endif 614 | 615 | /* 616 | * ZVEC_GENERATE_IMPL(T, Name) 617 | * 618 | * Primary generation macro. 619 | * 620 | * Use manually via: 621 | * #define REGISTER_ZVEC_TYPES(X) \ 622 | * X(int, Int) \ 623 | * X(float, Float) \ 624 | * X(MyType, MyType) 625 | * #include "zvec.h" 626 | * 627 | * This creates: 628 | * • struct zvec_Int / zvec_Float, etc. 629 | * • All functions: zvec_push_Int, zvec_reserve_Float, etc. 630 | * • Full _Generic dispatch. 631 | * • C++ traits specialization for z_vec::vector 632 | * 633 | * Fast path: returns int (Z_OK / Z_ENOMEM), asserts on logic errors. 634 | * Safe path (when zerror.h present): returns zres / zresult. 635 | */ 636 | #define ZVEC_GENERATE_IMPL(T, Name) \ 637 | \ 638 | typedef T zvec_T_##Name; \ 639 | \ 640 | typedef struct \ 641 | { \ 642 | T *data; \ 643 | size_t length; \ 644 | size_t capacity; \ 645 | } zvec_##Name; \ 646 | \ 647 | /* Forward declaration for C++ allocators to see. */ \ 648 | static inline int zvec_reserve_##Name(zvec_##Name *v, size_t new_cap); \ 649 | \ 650 | ZVEC_IMPL_ALLOC(T, Name) \ 651 | \ 652 | static inline zvec_##Name zvec_init_capacity_##Name(size_t cap) \ 653 | { \ 654 | zvec_##Name v; \ 655 | memset(&v, 0, sizeof(zvec_##Name)); \ 656 | if (cap > 0) \ 657 | { \ 658 | zvec_reserve_##Name(&v, cap); \ 659 | } \ 660 | return v; \ 661 | } \ 662 | \ 663 | static inline zvec_##Name zvec_from_array_##Name(const T *arr, size_t count) \ 664 | { \ 665 | zvec_##Name v = zvec_init_capacity_##Name(count); \ 666 | if (v.data) \ 667 | { \ 668 | size_t i; \ 669 | for(i = 0; ilength; \ 681 | } \ 682 | \ 683 | static inline T *zvec_push_slot_##Name(zvec_##Name *v) \ 684 | { \ 685 | if (v->length >= v->capacity) \ 686 | { \ 687 | size_t new_cap = Z_GROWTH_FACTOR(v->capacity); \ 688 | if (Z_OK != zvec_reserve_##Name(v, new_cap)) \ 689 | { \ 690 | return NULL; \ 691 | } \ 692 | } \ 693 | return &v->data[v->length++]; \ 694 | } \ 695 | \ 696 | static inline int zvec_push_##Name(zvec_##Name *v, T value) \ 697 | { \ 698 | T *slot = zvec_push_slot_##Name(v); \ 699 | if (!slot) \ 700 | { \ 701 | return Z_ENOMEM; \ 702 | } \ 703 | *slot = value; \ 704 | return Z_OK; \ 705 | } \ 706 | \ 707 | static inline int zvec_extend_##Name(zvec_##Name *v, const T *items, size_t count) \ 708 | { \ 709 | if (v->length + count > v->capacity) \ 710 | { \ 711 | size_t new_cap = v->capacity ? v->capacity : Z_GROWTH_FACTOR(0); \ 712 | while (new_cap < v->length + count) \ 713 | { \ 714 | new_cap = Z_GROWTH_FACTOR(new_cap); \ 715 | } \ 716 | if (Z_OK != zvec_reserve_##Name(v, new_cap)) \ 717 | { \ 718 | return Z_ENOMEM; \ 719 | } \ 720 | } \ 721 | size_t i; \ 722 | for( i = 0; idata[v->length + i] = items[i]; \ 725 | } \ 726 | v->length += count; \ 727 | return Z_OK; \ 728 | } \ 729 | \ 730 | static inline void zvec_pop_##Name(zvec_##Name *v) \ 731 | { \ 732 | assert(v->length > 0 && "Popping empty vector"); \ 733 | v->length--; \ 734 | } \ 735 | \ 736 | static inline T zvec_pop_get_##Name(zvec_##Name *v) \ 737 | { \ 738 | assert(v->length > 0 && "Vector is empty"); \ 739 | return v->data[--v->length]; \ 740 | } \ 741 | \ 742 | static inline T *zvec_at_##Name(zvec_##Name *v, size_t index) \ 743 | { \ 744 | return (index < v->length) ? &v->data[index] : NULL; \ 745 | } \ 746 | \ 747 | static inline T *zvec_data_##Name(zvec_##Name *v) \ 748 | { \ 749 | return v->data; \ 750 | } \ 751 | \ 752 | static inline T *zvec_last_##Name(zvec_##Name *v) \ 753 | { \ 754 | return (v->length > 0) ? &v->data[v->length - 1] : NULL; \ 755 | } \ 756 | \ 757 | static inline void zvec_swap_remove_##Name(zvec_##Name *v, size_t index) \ 758 | { \ 759 | if (index >= v->length) return; \ 760 | v->data[index] = v->data[--v->length]; \ 761 | } \ 762 | \ 763 | static inline void zvec_clear_##Name(zvec_##Name *v) \ 764 | { \ 765 | v->length = 0; \ 766 | } \ 767 | \ 768 | static inline void zvec_reverse_##Name(zvec_##Name *v) \ 769 | { \ 770 | if (v->length < 2) \ 771 | { \ 772 | return; \ 773 | } \ 774 | size_t i = 0; \ 775 | size_t j = v->length - 1; \ 776 | while (i < j) \ 777 | { \ 778 | T temp = v->data[i]; \ 779 | v->data[i] = v->data[j]; \ 780 | v->data[j] = temp; \ 781 | i++; \ 782 | j--; \ 783 | } \ 784 | } \ 785 | \ 786 | static inline void zvec_sort_##Name(zvec_##Name *v, \ 787 | int (*compar)(const T *, const T *)) \ 788 | { \ 789 | if (v->length > 1) \ 790 | { \ 791 | qsort(v->data, v->length, sizeof(T), \ 792 | (int(*)(const void *, const void *))compar); \ 793 | } \ 794 | } \ 795 | \ 796 | static inline T *zvec_bsearch_##Name(zvec_##Name *v, const T *key, \ 797 | int (*compar)(const T *, const T *)) \ 798 | { \ 799 | if (0 == v->length) \ 800 | { \ 801 | return NULL; \ 802 | } \ 803 | return (T *)bsearch(key, v->data, v->length, sizeof(T), \ 804 | (int(*)(const void *, const void *))compar); \ 805 | } \ 806 | \ 807 | static inline T *zvec_lower_bound_##Name(zvec_##Name *v, const T *key, \ 808 | int (*compar)(const T *, const T *)) \ 809 | { \ 810 | size_t l = 0; \ 811 | size_t r = v->length; \ 812 | while (l < r) \ 813 | { \ 814 | size_t mid = l + (r - l) / 2; \ 815 | if (compar((const T *)&v->data[mid], key) < 0) \ 816 | { \ 817 | l = mid + 1; \ 818 | } \ 819 | else \ 820 | { \ 821 | r = mid; \ 822 | } \ 823 | } \ 824 | return (l < v->length) ? &v->data[l] : NULL; \ 825 | } \ 826 | \ 827 | /* Inject safe API. */ \ 828 | ZVEC_GEN_SAFE_IMPL(T, Name) 829 | 830 | // Dispatch table entries for _Generic. 831 | #define PUSH_ENTRY(T, Name) zvec_##Name *: zvec_push_##Name, 832 | #define PUSH_SLOT_ENTRY(T, Name) zvec_##Name *: zvec_push_slot_##Name, 833 | #define EXTEND_ENTRY(T, Name) zvec_##Name *: zvec_extend_##Name, 834 | #define RESERVE_ENTRY(T, Name) zvec_##Name *: zvec_reserve_##Name, 835 | #define IS_EMPTY_ENTRY(T, Name) zvec_##Name *: zvec_is_empty_##Name, 836 | #define AT_ENTRY(T, Name) zvec_##Name *: zvec_at_##Name, 837 | #define DATA_ENTRY(T, Name) zvec_##Name *: zvec_data_##Name, 838 | #define LAST_ENTRY(T, Name) zvec_##Name *: zvec_last_##Name, 839 | #define FREE_ENTRY(T, Name) zvec_##Name *: zvec_free_##Name, 840 | #define POP_ENTRY(T, Name) zvec_##Name *: zvec_pop_##Name, 841 | #define POP_GET_ENTRY(T, Name) zvec_##Name *: zvec_pop_get_##Name, 842 | #define SHRINK_ENTRY(T, Name) zvec_##Name *: zvec_shrink_to_fit_##Name, 843 | #define REMOVE_ENTRY(T, Name) zvec_##Name *: zvec_remove_##Name, 844 | #define SWAP_REM_ENTRY(T, Name) zvec_##Name *: zvec_swap_remove_##Name, 845 | #define CLEAR_ENTRY(T, Name) zvec_##Name *: zvec_clear_##Name, 846 | #define REVERSE_ENTRY(T, Name) zvec_##Name *: zvec_reverse_##Name, 847 | #define SORT_ENTRY(T, Name) zvec_##Name *: zvec_sort_##Name, 848 | #define BSEARCH_ENTRY(T, Name) zvec_##Name *: zvec_bsearch_##Name, 849 | #define LOWER_BOUND_ENTRY(T, Name) zvec_##Name *: zvec_lower_bound_##Name, 850 | 851 | #if Z_HAS_ZERROR 852 | # define RESERVE_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_reserve_safe_##Name, 853 | # define PUSH_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_push_safe_##Name, 854 | # define POP_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_pop_safe_##Name, 855 | # define AT_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_at_safe_##Name, 856 | # define LAST_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_last_safe_##Name, 857 | #endif 858 | 859 | #ifndef REGISTER_ZVEC_TYPES 860 | # if defined(__has_include) && __has_include("z_registry.h") 861 | # include "z_registry.h" 862 | # endif 863 | #endif 864 | 865 | #ifndef REGISTER_ZVEC_TYPES 866 | # define REGISTER_ZVEC_TYPES(X) 867 | #endif 868 | 869 | #ifndef Z_AUTOGEN_VECS 870 | # define Z_AUTOGEN_VECS(X) 871 | #endif 872 | 873 | #define Z_ALL_VECS(X) \ 874 | Z_AUTOGEN_VECS(X) \ 875 | REGISTER_ZVEC_TYPES(X) 876 | 877 | Z_ALL_VECS(ZVEC_GENERATE_IMPL) 878 | 879 | // Public convenience macros. 880 | 881 | #define zvec_from(Name, ...) \ 882 | zvec_from_array_##Name((zvec_T_##Name[]){__VA_ARGS__}, \ 883 | sizeof((zvec_T_##Name[]){__VA_ARGS__}) / sizeof(zvec_T_##Name)) 884 | 885 | #define zvec_init(Name) zvec_init_capacity_##Name(0) 886 | #define zvec_init_with_cap(Name, cap) zvec_init_capacity_##Name(cap) 887 | 888 | #if Z_HAS_CLEANUP 889 | # define zvec_autofree(Name) Z_CLEANUP(zvec_free_##Name) zvec_##Name 890 | #endif 891 | 892 | // Generic dispatch using _Generic. 893 | 894 | #ifdef __cplusplus 895 | // C++ Overload Dispatch 896 | # define zvec_push(v, val) zvec_push_dispatch(v, val) 897 | # define zvec_push_slot(v) zvec_push_slot_dispatch(v) 898 | # define zvec_extend(v, arr, count) zvec_extend_dispatch(v, arr, count) 899 | # define zvec_reserve(v, cap) zvec_reserve_dispatch(v, cap) 900 | # define zvec_is_empty(v) zvec_is_empty_dispatch(v) 901 | # define zvec_at(v, idx) zvec_at_dispatch(v, idx) 902 | # define zvec_data(v) zvec_data_dispatch(v) 903 | # define zvec_last(v) zvec_last_dispatch(v) 904 | # define zvec_free(v) zvec_free_dispatch(v) 905 | # define zvec_pop(v) zvec_pop_dispatch(v) 906 | # define zvec_pop_get(v) zvec_pop_get_dispatch(v) 907 | # define zvec_shrink_to_fit(v) zvec_shrink_to_fit_dispatch(v) 908 | # define zvec_remove(v, i) zvec_remove_dispatch(v, i) 909 | # define zvec_swap_remove(v, i) zvec_swap_remove_dispatch(v, i) 910 | # define zvec_clear(v) zvec_clear_dispatch(v) 911 | # define zvec_reverse(v) zvec_reverse_dispatch(v) 912 | # define zvec_sort(v, cmp) zvec_sort_dispatch(v, cmp) 913 | # define zvec_bsearch(v, k, c) zvec_bsearch_dispatch(v, k, c) 914 | # define zvec_lower_bound(v, k, c) zvec_lower_bound_dispatch(v, k, c) 915 | #else 916 | // C _Generic Dispatch 917 | # define zvec_push(v, val) _Generic((v), Z_ALL_VECS(PUSH_ENTRY) default: 0)(v, val) 918 | # define zvec_push_slot(v) _Generic((v), Z_ALL_VECS(PUSH_SLOT_ENTRY) default: (void *)0)(v) 919 | # define zvec_extend(v, arr, count) _Generic((v), Z_ALL_VECS(EXTEND_ENTRY) default: 0)(v, arr, count) 920 | # define zvec_reserve(v, cap) _Generic((v), Z_ALL_VECS(RESERVE_ENTRY) default: 0)(v, cap) 921 | # define zvec_is_empty(v) _Generic((v), Z_ALL_VECS(IS_EMPTY_ENTRY) default: 0)(v) 922 | # define zvec_at(v, idx) _Generic((v), Z_ALL_VECS(AT_ENTRY) default: (void *)0)(v, idx) 923 | # define zvec_data(v) _Generic((v), Z_ALL_VECS(DATA_ENTRY) default: (void *)0)(v) 924 | # define zvec_last(v) _Generic((v), Z_ALL_VECS(LAST_ENTRY) default: (void *)0)(v) 925 | # define zvec_free(v) _Generic((v), Z_ALL_VECS(FREE_ENTRY) default: (void)0)(v) 926 | # define zvec_pop(v) _Generic((v), Z_ALL_VECS(POP_ENTRY) default: (void)0)(v) 927 | # define zvec_pop_get(v) _Generic((v), Z_ALL_VECS(POP_GET_ENTRY) default: (void)0)(v) 928 | # define zvec_shrink_to_fit(v) _Generic((v), Z_ALL_VECS(SHRINK_ENTRY) default: (void)0)(v) 929 | # define zvec_remove(v, i) _Generic((v), Z_ALL_VECS(REMOVE_ENTRY) default: (void)0)(v, i) 930 | # define zvec_swap_remove(v, i) _Generic((v), Z_ALL_VECS(SWAP_REM_ENTRY) default: (void)0)(v, i) 931 | # define zvec_clear(v) _Generic((v), Z_ALL_VECS(CLEAR_ENTRY) default: (void)0)(v) 932 | # define zvec_reverse(v) _Generic((v), Z_ALL_VECS(REVERSE_ENTRY) default: (void)0)(v) 933 | # define zvec_sort(v, cmp) _Generic((v), Z_ALL_VECS(SORT_ENTRY) default: (void)0)(v, cmp) 934 | # define zvec_bsearch(v, k, c) _Generic((v), Z_ALL_VECS(BSEARCH_ENTRY) default: (void *)0)(v, k, c) 935 | # define zvec_lower_bound(v, k, c) _Generic((v), Z_ALL_VECS(LOWER_BOUND_ENTRY) default: (void *)0)(v, k, c) 936 | #endif 937 | 938 | /* * Explicit declaration macro (portable C99) 939 | * Usage: zvec_foreach_decl(Int, &vec, it) { ... } 940 | */ 941 | #define zvec_foreach_decl(Name, v, iter) \ 942 | for (zvec_T_##Name *iter = (v)->data; \ 943 | iter < (v)->data + (v)->length; \ 944 | ++iter) 945 | 946 | // Smart iteration helpers (auto-inference). 947 | #if defined(__GNUC__) || defined(__clang__) 948 | 949 | #define zvec_foreach(v, iter) \ 950 | for (__typeof__((v)->data) iter = (v)->data; \ 951 | iter < (v)->data + (v)->length; \ 952 | ++iter) 953 | 954 | #else 955 | 956 | /* Standard C fallback: User must declare 'iter' before loop. 957 | * Usage: int *it; zvec_foreach(&vec, it) { ... } 958 | */ 959 | #define zvec_foreach(v, iter) \ 960 | for ((iter) = (v)->data; \ 961 | (iter) < (v)->data + (v)->length; \ 962 | ++(iter)) 963 | 964 | #endif 965 | 966 | // Safe API dispatch (zerror.h required). 967 | #if Z_HAS_ZERROR && !defined(__cplusplus) 968 | static inline zres zres_err_dummy(void *v, ...) 969 | { 970 | (void)v; 971 | return zres_err(zerr_create(-1, "Unknown vector type")); 972 | } 973 | 974 | # define zvec_reserve_safe(v, cap) \ 975 | _Generic((v), Z_ALL_VECS(RESERVE_SAFE_ENTRY) default: zres_err_dummy)(v, cap, __FILE__, __LINE__, __func__) 976 | 977 | # define zvec_push_safe(v, val) \ 978 | _Generic((v), Z_ALL_VECS(PUSH_SAFE_ENTRY) default: zres_err_dummy)(v, val, __FILE__, __LINE__, __func__) 979 | 980 | # define zvec_pop_safe(v) \ 981 | _Generic((v), Z_ALL_VECS(POP_SAFE_ENTRY) default: zres_err_dummy)(v, __FILE__, __LINE__, __func__) 982 | 983 | # define zvec_at_safe(v, i) \ 984 | _Generic((v), Z_ALL_VECS(AT_SAFE_ENTRY) default: zres_err_dummy)(v, i, __FILE__, __LINE__, __func__) 985 | 986 | # define zvec_last_safe(v) \ 987 | _Generic((v), Z_ALL_VECS(LAST_SAFE_ENTRY) default: zres_err_dummy)(v, __FILE__, __LINE__, __func__) 988 | #endif 989 | 990 | // Optional short names (never enabled by default). 991 | #ifdef ZVEC_SHORT_NAMES 992 | # define vec(Name) zvec_##Name 993 | # define vec_init zvec_init 994 | # define vec_init_with_cap zvec_init_with_cap 995 | # define vec_from zvec_from 996 | # define vec_autofree zvec_autofree 997 | # define vec_push zvec_push 998 | # define vec_push_slot zvec_push_slot 999 | # define vec_extend zvec_extend 1000 | # define vec_reserve zvec_reserve 1001 | # define vec_is_empty zvec_is_empty 1002 | # define vec_at zvec_at 1003 | # define vec_data zvec_data 1004 | # define vec_last zvec_last 1005 | # define vec_free zvec_free 1006 | # define vec_pop zvec_pop 1007 | # define vec_pop_get zvec_pop_get 1008 | # define vec_shrink_to_fit zvec_shrink_to_fit 1009 | # define vec_remove zvec_remove 1010 | # define vec_swap_remove zvec_swap_remove 1011 | # define vec_clear zvec_clear 1012 | # define vec_reverse zvec_reverse 1013 | # define vec_sort zvec_sort 1014 | # define vec_bsearch zvec_bsearch 1015 | # define vec_lower_bound zvec_lower_bound 1016 | # define vec_foreach zvec_foreach 1017 | # if Z_HAS_ZERROR && !defined(__cplusplus) 1018 | # define vec_reserve_safe zvec_reserve_safe 1019 | # define vec_push_safe zvec_push_safe 1020 | # define vec_pop_safe zvec_pop_safe 1021 | # define vec_at_safe zvec_at_safe 1022 | # define vec_last_safe zvec_last_safe 1023 | # endif 1024 | #endif 1025 | 1026 | #ifdef __cplusplus 1027 | } // extern "C" 1028 | 1029 | Z_ALL_VECS(ZVEC_CPP_DISPATCH_IMPL) 1030 | 1031 | namespace z_vec 1032 | { 1033 | #define ZVEC_CPP_TRAITS(T, Name) \ 1034 | template <> struct traits \ 1035 | { \ 1036 | using c_type = ::zvec_##Name; \ 1037 | static inline void init(c_type &v) \ 1038 | { \ 1039 | v = ::zvec_init_capacity_##Name(0); \ 1040 | } \ 1041 | \ 1042 | static inline void init_cap(c_type &v, size_t c) \ 1043 | { \ 1044 | v = ::zvec_init_capacity_##Name(c); \ 1045 | } \ 1046 | \ 1047 | static inline void free(c_type &v) \ 1048 | { \ 1049 | ::zvec_free_##Name(&v); \ 1050 | } \ 1051 | \ 1052 | static inline int push(c_type &v, T val) \ 1053 | { \ 1054 | return ::zvec_push_##Name(&v, val); \ 1055 | } \ 1056 | \ 1057 | static inline int extend(c_type &v, const T *arr, size_t n) \ 1058 | { \ 1059 | return ::zvec_extend_##Name(&v, arr, n); \ 1060 | } \ 1061 | \ 1062 | static inline int reserve(c_type &v, size_t n) \ 1063 | { \ 1064 | return ::zvec_reserve_##Name(&v, n); \ 1065 | } \ 1066 | \ 1067 | static inline void pop(c_type &v) \ 1068 | { \ 1069 | ::zvec_pop_##Name(&v); \ 1070 | } \ 1071 | \ 1072 | static inline T pop_get(c_type &v) \ 1073 | { \ 1074 | return ::zvec_pop_get_##Name(&v); \ 1075 | } \ 1076 | \ 1077 | static inline void remove(c_type &v, size_t i) \ 1078 | { \ 1079 | ::zvec_remove_##Name(&v, i); \ 1080 | } \ 1081 | \ 1082 | static inline void swap_remove(c_type &v, size_t i) \ 1083 | { \ 1084 | ::zvec_swap_remove_##Name(&v, i); \ 1085 | } \ 1086 | \ 1087 | static inline void clear(c_type &v) \ 1088 | { \ 1089 | ::zvec_clear_##Name(&v); \ 1090 | } \ 1091 | \ 1092 | static inline void shrink(c_type &v) \ 1093 | { \ 1094 | ::zvec_shrink_to_fit_##Name(&v); \ 1095 | } \ 1096 | \ 1097 | static inline void reverse(c_type &v) \ 1098 | { \ 1099 | ::zvec_reverse_##Name(&v); \ 1100 | } \ 1101 | }; 1102 | 1103 | Z_ALL_VECS(ZVEC_CPP_TRAITS) 1104 | } 1105 | #endif // __cplusplus 1106 | 1107 | #endif // ZVEC_H 1108 | -------------------------------------------------------------------------------- /zvec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * GENERATED FILE - DO NOT EDIT DIRECTLY 3 | * Source: zvec.c 4 | * 5 | * This file is part of the z-libs collection: https://github.com/z-libs 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | 10 | /* ============================================================================ 11 | z-libs Common Definitions (Bundled) 12 | This block is auto-generated. It is guarded so that if you include multiple 13 | z-libs it is only defined once. 14 | ============================================================================ */ 15 | #ifndef Z_COMMON_BUNDLED 16 | #define Z_COMMON_BUNDLED 17 | 18 | 19 | /* 20 | * zcommon.h — Common definitions for the Zen Development Kit (ZDK) 21 | * Part of ZDK 22 | * 23 | * This header defines shared macros, error codes, and compiler extensions 24 | * used across all ZDK libraries. 25 | * 26 | * License: MIT 27 | */ 28 | 29 | #ifndef ZCOMMON_H 30 | #define ZCOMMON_H 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | // Return codes and error handling. 39 | 40 | // Success. 41 | #define Z_OK 0 42 | #define Z_FOUND 1 // Element found (positive). 43 | 44 | // Generic errors. 45 | #define Z_ERR -1 // Generic error. 46 | 47 | // Resource errors. 48 | #define Z_ENOMEM -2 // Out of memory (malloc/realloc failed). 49 | 50 | // Access errors. 51 | #define Z_EOOB -3 // Out of bounds / range error. 52 | #define Z_EEMPTY -4 // Container is empty. 53 | #define Z_ENOTFOUND -5 // Element not found. 54 | 55 | // Logic errors. 56 | #define Z_EINVAL -6 // Invalid argument / parameter. 57 | #define Z_EEXIST -7 // Element already exists (for example, unique keys). 58 | 59 | // Memory management. 60 | 61 | /* * If the user hasn't defined their own allocator, use the standard C library. 62 | * To override globally, define these macros before including any ZDK header. 63 | */ 64 | #ifndef Z_MALLOC 65 | # include 66 | # define Z_MALLOC(sz) malloc(sz) 67 | # define Z_CALLOC(n, sz) calloc(n, sz) 68 | # define Z_REALLOC(p, sz) realloc(p, sz) 69 | # define Z_FREE(p) free(p) 70 | #endif 71 | 72 | 73 | // Compiler extensions and optimization. 74 | 75 | /* * We check for GCC/Clang features to enable RAII-style cleanup and optimization hints. 76 | * Define Z_NO_EXTENSIONS to disable this manually. 77 | */ 78 | #if !defined(Z_NO_EXTENSIONS) && (defined(__GNUC__) || defined(__clang__)) 79 | 80 | # define Z_HAS_CLEANUP 1 81 | 82 | // RAII cleanup (destructors). 83 | // Usage: zvec_autofree(Int) v = zvec_init(Int); 84 | # define Z_CLEANUP(func) __attribute__((cleanup(func))) 85 | 86 | // Warn if the return value (e.g., an Error Result) is ignored. 87 | # define Z_NODISCARD __attribute__((warn_unused_result)) 88 | 89 | // Branch prediction hints for the compiler. 90 | # define Z_LIKELY(x) __builtin_expect(!!(x), 1) 91 | # define Z_UNLIKELY(x) __builtin_expect(!!(x), 0) 92 | 93 | #else 94 | 95 | # define Z_HAS_CLEANUP 0 96 | # define Z_CLEANUP(func) 97 | # define Z_NODISCARD 98 | # define Z_LIKELY(x) (x) 99 | # define Z_UNLIKELY(x) (x) 100 | 101 | #endif 102 | 103 | 104 | // Metaprogramming and internal utils. 105 | 106 | /* * Markers for the Z-Scanner tool to find type definitions. 107 | * For the C compiler, they are no-ops (they compile to nothing). 108 | */ 109 | #define DEFINE_VEC_TYPE(T, Name) 110 | #define DEFINE_LIST_TYPE(T, Name) 111 | #define DEFINE_MAP_TYPE(Key, Val, Name) 112 | #define DEFINE_STABLE_MAP_TYPE(Key, Val, Name) 113 | 114 | // Token concatenation macros (useful for unique variable names in macros). 115 | #define Z_CONCAT_(a, b) a ## b 116 | #define Z_CONCAT(a, b) Z_CONCAT_(a, b) 117 | #define Z_UNIQUE(prefix) Z_CONCAT(prefix, __LINE__) 118 | 119 | // Growth strategy. 120 | 121 | /* * Determines how containers expand when full. 122 | * Default is 2.0x (Geometric Growth). 123 | * 124 | * Optimization note: 125 | * 2.0x minimizes realloc calls but can waste memory. 126 | * 1.5x is often better for memory fragmentation and reuse. 127 | */ 128 | #ifndef Z_GROWTH_FACTOR 129 | // Default: Double capacity (2.0x). 130 | # define Z_GROWTH_FACTOR(cap) ((cap) == 0 ? 32 : (cap) * 2) 131 | 132 | // Alternative: 1.5x Growth (Uncomment to use in your project). 133 | // #define Z_GROWTH_FACTOR(cap) ((cap) == 0 ? 32 : (cap) + (cap) / 2) 134 | #endif 135 | 136 | #endif // ZCOMMON_H 137 | 138 | 139 | #endif // Z_COMMON_BUNDLED 140 | /* ============================================================================ */ 141 | 142 | /* 143 | * zvec.h — Type-safe, zero-overhead dynamic arrays 144 | * Part of Zen Development Kit (ZDK) 145 | * 146 | * This is a macro-generated, single-header dynamic array library that produces 147 | * fully type-safe vector implementations at compile time. It supports both C and C++ 148 | * with zero-cost abstraction. 149 | * 150 | * Features: 151 | * • C11 _Generic interface (zvec_push(v, x)) 152 | * • Full RAII C++ wrapper in namespace z_vec::vector 153 | * • Fast path (asserts + int error codes) and safe path (zres) 154 | * • Optional short names via ZVEC_SHORT_NAMES 155 | * • Automatic type registration via z_registry.h or manual DEFINE_ macros 156 | * 157 | * License: MIT 158 | * Author: Zuhaitz 159 | * Repository: https://github.com/z-libs/zvec.h 160 | * Version: 1.0.3 161 | */ 162 | 163 | #ifndef ZVEC_H 164 | #define ZVEC_H 165 | // [Bundled] "zcommon.h" is included inline in this same file 166 | #include 167 | #include 168 | #include 169 | 170 | #if defined(__has_include) && __has_include("zerror.h") 171 | # include "zerror.h" 172 | # define Z_HAS_ZERROR 1 173 | #elif defined(ZERROR_H) 174 | # define Z_HAS_ZERROR 1 175 | #else 176 | # define Z_HAS_ZERROR 0 177 | #endif 178 | 179 | // C++ interop preamble. 180 | #ifdef __cplusplus 181 | #include 182 | #include 183 | #include 184 | #include 185 | #include 186 | #include 187 | 188 | namespace z_vec 189 | { 190 | // Traits struct - connects C++ wrapper to generated C functions. 191 | template 192 | struct traits 193 | { 194 | static_assert(0 == sizeof(T), "No zvec implementation registered for this type. " 195 | "Use REGISTER_ZVEC_TYPES() or Z_AUTOGEN_VECS() before including zvec.h."); 196 | }; 197 | 198 | // C++ RAII vector wrapper. 199 | template 200 | class vector 201 | { 202 | using Traits = traits; 203 | using CType = typename Traits::c_type; 204 | 205 | CType inner; 206 | 207 | public: 208 | using value_type = T; 209 | using size_type = size_t; 210 | using difference_type = std::ptrdiff_t; 211 | using pointer = T *; 212 | using const_pointer = const T *; 213 | using iterator = T *; 214 | using const_iterator = const T *; 215 | 216 | // Constructors and destructor (RAII). 217 | 218 | vector() 219 | { 220 | Traits::init(inner); 221 | } 222 | 223 | explicit vector(size_t capacity) 224 | { 225 | Traits::init_cap(inner, capacity); 226 | } 227 | 228 | vector(std::initializer_list init) 229 | { 230 | Traits::init_cap(inner, init.size()); 231 | Traits::extend(inner, init.begin(), init.size()); 232 | } 233 | 234 | vector(const vector &other) 235 | { 236 | Traits::init_cap(inner, other.size()); 237 | Traits::extend(inner, other.data(), other.size()); 238 | } 239 | 240 | vector(vector &&other) noexcept 241 | { 242 | inner = other.inner; 243 | Traits::init(other.inner); 244 | } 245 | 246 | ~vector() 247 | { 248 | Traits::free(inner); 249 | } 250 | 251 | vector &operator=(const vector &other) 252 | { 253 | if (&other != this) 254 | { 255 | Traits::free(inner); 256 | Traits::init_cap(inner, other.size()); 257 | Traits::extend(inner, other.data(), other.size()); 258 | } 259 | return *this; 260 | } 261 | 262 | vector &operator=(vector &&other) noexcept 263 | { 264 | if (&other != this) 265 | { 266 | Traits::free(inner); 267 | inner = other.inner; 268 | Traits::init(other.inner); 269 | } 270 | return *this; 271 | } 272 | 273 | // Accessors. 274 | 275 | T *data() 276 | { 277 | return inner.data; 278 | } 279 | 280 | const T *data() const 281 | { 282 | return inner.data; 283 | } 284 | 285 | size_t size() const 286 | { 287 | return inner.length; 288 | } 289 | 290 | size_t capacity() const 291 | { 292 | return inner.capacity; 293 | } 294 | 295 | bool empty() const 296 | { 297 | return 0 == inner.length; 298 | } 299 | 300 | T &operator[](size_t idx) 301 | { 302 | return inner.data[idx]; 303 | } 304 | 305 | const T &operator[](size_t idx) const 306 | { 307 | return inner.data[idx]; 308 | } 309 | 310 | T &at(size_t idx) 311 | { 312 | if (idx >= size()) 313 | { 314 | throw std::out_of_range("vector::at"); 315 | } 316 | return inner.data[idx]; 317 | } 318 | 319 | const T &at(size_t idx) const 320 | { 321 | if (idx >= size()) throw std::out_of_range("vector::at"); 322 | return inner.data[idx]; 323 | } 324 | 325 | T &front() 326 | { 327 | return inner.data[0]; 328 | } 329 | 330 | const T &front() const 331 | { 332 | return inner.data[0]; 333 | } 334 | 335 | T &back() 336 | { 337 | return inner.data[inner.length - 1]; 338 | } 339 | 340 | const T &back() const 341 | { 342 | return inner.data[inner.length - 1]; 343 | } 344 | 345 | // Modifiers. 346 | 347 | void push_back(const T &val) 348 | { 349 | if (Z_OK != Traits::push(inner, val)) 350 | { 351 | throw std::bad_alloc(); 352 | } 353 | } 354 | 355 | void pop_back() 356 | { 357 | Traits::pop(inner); 358 | } 359 | 360 | void clear() 361 | { 362 | Traits::clear(inner); 363 | } 364 | 365 | void reserve(size_t cap) 366 | { 367 | if (Z_OK != Traits::reserve(inner, cap)) 368 | { 369 | throw std::bad_alloc(); 370 | } 371 | } 372 | 373 | void shrink_to_fit() 374 | { 375 | Traits::shrink(inner); 376 | } 377 | 378 | void reverse() 379 | { 380 | Traits::reverse(inner); 381 | } 382 | 383 | void remove(size_t idx) 384 | { 385 | Traits::remove(inner, idx); 386 | } 387 | 388 | void swap_remove(size_t idx) 389 | { 390 | Traits::swap_remove(inner, idx); 391 | } 392 | 393 | // Iterators. 394 | 395 | iterator begin() 396 | { 397 | return inner.data; 398 | } 399 | 400 | iterator end() 401 | { 402 | return inner.data + inner.length; 403 | } 404 | 405 | const_iterator begin() const 406 | { 407 | return inner.data; 408 | } 409 | 410 | const_iterator end() const 411 | { 412 | return inner.data + inner.length; 413 | } 414 | }; 415 | } 416 | 417 | extern "C" { 418 | #endif 419 | 420 | // Allocator overrides (user may redefine). 421 | #ifndef ZVEC_MALLOC 422 | #define ZVEC_MALLOC(sz) Z_MALLOC(sz) 423 | #endif 424 | 425 | #ifndef ZVEC_CALLOC 426 | #define ZVEC_CALLOC(n, sz) Z_CALLOC(n, sz) 427 | #endif 428 | 429 | #ifndef ZVEC_REALLOC 430 | #define ZVEC_REALLOC(p, sz) Z_REALLOC(p, sz) 431 | #endif 432 | 433 | #ifndef ZVEC_FREE 434 | #define ZVEC_FREE(p) Z_FREE(p) 435 | #endif 436 | 437 | /* 438 | * Safe API generation (requires zerror.h). 439 | * 440 | * When Z_HAS_ZERROR is true, each generated vector type gets safe variants. 441 | * * MODIFIED: Disabled for C++ to prevent errors with unions containing classes. 442 | */ 443 | #if Z_HAS_ZERROR && !defined(__cplusplus) 444 | 445 | static inline zerr zvec_err_impl(int code, const char *msg, 446 | const char *file, int line, const char *func) 447 | { 448 | return zerr_create_impl(code, file, line, func, "%s", msg); 449 | } 450 | 451 | #define ZVEC_GEN_SAFE_IMPL(T, Name) \ 452 | DEFINE_RESULT(T, Res_##Name) \ 453 | \ 454 | static inline zres zvec_push_safe_##Name(zvec_##Name *v, T value, \ 455 | const char *f, int l, const char *fn) \ 456 | { \ 457 | if (v->length >= v->capacity) \ 458 | { \ 459 | size_t new_cap = Z_GROWTH_FACTOR(v->capacity); \ 460 | T *new_data = (T *)ZVEC_REALLOC(v->data, new_cap * sizeof(T)); \ 461 | if (!new_data) \ 462 | { \ 463 | return zres_err(zvec_err_impl(Z_ENOMEM, "Vector Push OOM", f, l, fn)); \ 464 | } \ 465 | v->data = new_data; \ 466 | v->capacity = new_cap; \ 467 | } \ 468 | v->data[v->length++] = value; \ 469 | return zres_ok(); \ 470 | } \ 471 | \ 472 | static inline zres zvec_reserve_safe_##Name(zvec_##Name *v, size_t cap, \ 473 | const char *f, int l, const char *fn) \ 474 | { \ 475 | if (cap <= v->capacity) \ 476 | { \ 477 | return zres_ok(); \ 478 | } \ 479 | T *new_data = (T *)ZVEC_REALLOC(v->data, cap * sizeof(T)); \ 480 | if (!new_data) \ 481 | { \ 482 | return zres_err(zvec_err_impl(Z_ENOMEM, "Vector Reserve OOM", f, l, fn)); \ 483 | } \ 484 | v->data = new_data; \ 485 | v->capacity = cap; \ 486 | return zres_ok(); \ 487 | } \ 488 | \ 489 | static inline Res_##Name zvec_pop_safe_##Name(zvec_##Name *v, \ 490 | const char *f, int l, const char *fn) \ 491 | { \ 492 | if (0 == v->length) \ 493 | { \ 494 | return Res_##Name##_err(zvec_err_impl(Z_EEMPTY, "Pop empty vec", f, l, fn)); \ 495 | } \ 496 | return Res_##Name##_ok(v->data[--v->length]); \ 497 | } \ 498 | \ 499 | static inline Res_##Name zvec_at_safe_##Name(zvec_##Name *v, size_t i, \ 500 | const char *f, int l, const char *fn) \ 501 | { \ 502 | if (i >= v->length) \ 503 | { \ 504 | return Res_##Name##_err(zvec_err_impl(Z_EOOB, "Index out of bounds", f, l, fn));\ 505 | } \ 506 | return Res_##Name##_ok(v->data[i]); \ 507 | } \ 508 | \ 509 | static inline Res_##Name zvec_last_safe_##Name(zvec_##Name *v, \ 510 | const char *f, int l, const char *fn) \ 511 | { \ 512 | if (0 == v->length) \ 513 | { \ 514 | return Res_##Name##_err(zvec_err_impl(Z_EEMPTY, "Vector is empty", f, l, fn)); \ 515 | } \ 516 | return Res_##Name##_ok(v->data[v->length - 1]); \ 517 | } 518 | 519 | #else 520 | # define ZVEC_GEN_SAFE_IMPL(T, Name) 521 | #endif 522 | 523 | // C++ compatibility layers. 524 | 525 | #ifdef __cplusplus 526 | # define ZVEC_IMPL_ALLOC(T, Name) \ 527 | static inline int zvec_reserve_##Name(zvec_##Name *v, size_t new_cap) \ 528 | { \ 529 | if (new_cap <= v->capacity) \ 530 | { \ 531 | return Z_OK; \ 532 | } \ 533 | try { \ 534 | T* new_data = new T[new_cap]; \ 535 | for (size_t i = 0; i < v->length; ++i) \ 536 | { \ 537 | new_data[i] = std::move(v->data[i]); \ 538 | } \ 539 | if (v->data) \ 540 | { \ 541 | delete[] v->data; \ 542 | } \ 543 | v->data = new_data; \ 544 | v->capacity = new_cap; \ 545 | } catch (...) { return Z_ENOMEM; } \ 546 | return Z_OK; \ 547 | } \ 548 | \ 549 | static inline void zvec_free_##Name(zvec_##Name *v) \ 550 | { \ 551 | if (v->data) \ 552 | { \ 553 | delete[] v->data; \ 554 | } \ 555 | v->data = NULL; \ 556 | v->length = 0; \ 557 | v->capacity = 0; \ 558 | } \ 559 | \ 560 | static inline void zvec_remove_##Name(zvec_##Name *v, size_t index) \ 561 | { \ 562 | if (index >= v->length) \ 563 | { \ 564 | return; \ 565 | } \ 566 | for (size_t i = index; i < v->length - 1; ++i) \ 567 | { \ 568 | v->data[i] = std::move(v->data[i + 1]); \ 569 | } \ 570 | v->data[v->length - 1] = T(); \ 571 | v->length--; \ 572 | } \ 573 | \ 574 | static inline void zvec_shrink_to_fit_##Name(zvec_##Name *v) \ 575 | { \ 576 | if (v->length == v->capacity) \ 577 | { \ 578 | return; \ 579 | } \ 580 | if (0 == v->length) \ 581 | { \ 582 | zvec_free_##Name(v); \ 583 | return; \ 584 | } \ 585 | try \ 586 | { \ 587 | T* new_data = new T[v->length]; \ 588 | for (size_t i = 0; i < v->length; ++i) \ 589 | { \ 590 | new_data[i] = std::move(v->data[i]); \ 591 | } \ 592 | if (v->data) delete[] v->data; \ 593 | v->data = new_data; \ 594 | v->capacity = v->length; \ 595 | } \ 596 | catch (...) {} \ 597 | } 598 | 599 | // C++ dispatch: generates inline overloads so C++ can find functions without _Generic. 600 | # define ZVEC_CPP_DISPATCH_IMPL(T, Name) \ 601 | static inline int zvec_reserve_dispatch(zvec_##Name *v, size_t n) \ 602 | { \ 603 | return zvec_reserve_##Name(v, n); \ 604 | } \ 605 | \ 606 | static inline int zvec_push_dispatch(zvec_##Name *v, T val) \ 607 | { \ 608 | return zvec_push_##Name(v, val); \ 609 | } \ 610 | \ 611 | static inline T* zvec_push_slot_dispatch(zvec_##Name *v) \ 612 | { \ 613 | return zvec_push_slot_##Name(v); \ 614 | } \ 615 | \ 616 | static inline int zvec_extend_dispatch(zvec_##Name *v, const T *arr, size_t n) \ 617 | { \ 618 | return zvec_extend_##Name(v, arr, n); \ 619 | } \ 620 | \ 621 | static inline int zvec_is_empty_dispatch(zvec_##Name *v) \ 622 | { \ 623 | return zvec_is_empty_##Name(v); \ 624 | } \ 625 | \ 626 | static inline T* zvec_at_dispatch(zvec_##Name *v, size_t i) \ 627 | { \ 628 | return zvec_at_##Name(v, i); \ 629 | } \ 630 | \ 631 | static inline T* zvec_data_dispatch(zvec_##Name *v) \ 632 | { \ 633 | return zvec_data_##Name(v); \ 634 | } \ 635 | \ 636 | static inline T* zvec_last_dispatch(zvec_##Name *v) \ 637 | { \ 638 | return zvec_last_##Name(v); \ 639 | } \ 640 | \ 641 | static inline void zvec_free_dispatch(zvec_##Name *v) \ 642 | { \ 643 | zvec_free_##Name(v); \ 644 | } \ 645 | \ 646 | static inline void zvec_pop_dispatch(zvec_##Name *v) \ 647 | { \ 648 | zvec_pop_##Name(v); \ 649 | } \ 650 | \ 651 | static inline T zvec_pop_get_dispatch(zvec_##Name *v) \ 652 | { \ 653 | return zvec_pop_get_##Name(v); \ 654 | } \ 655 | \ 656 | static inline void zvec_shrink_to_fit_dispatch(zvec_##Name *v) \ 657 | { \ 658 | zvec_shrink_to_fit_##Name(v); \ 659 | } \ 660 | \ 661 | static inline void zvec_remove_dispatch(zvec_##Name *v, size_t i) \ 662 | { \ 663 | zvec_remove_##Name(v, i); \ 664 | } \ 665 | \ 666 | static inline void zvec_swap_remove_dispatch(zvec_##Name *v, size_t i) \ 667 | { \ 668 | zvec_swap_remove_##Name(v, i); \ 669 | } \ 670 | \ 671 | static inline void zvec_clear_dispatch(zvec_##Name *v) \ 672 | { \ 673 | zvec_clear_##Name(v); \ 674 | } \ 675 | \ 676 | static inline void zvec_reverse_dispatch(zvec_##Name *v) \ 677 | { \ 678 | zvec_reverse_##Name(v); \ 679 | } \ 680 | \ 681 | static inline void zvec_sort_dispatch(zvec_##Name *v, \ 682 | int (*cmp)(const T*, const T*)) \ 683 | { \ 684 | zvec_sort_##Name(v, cmp); \ 685 | } \ 686 | \ 687 | static inline T* zvec_bsearch_dispatch(zvec_##Name *v, const T* k, \ 688 | int (*cmp)(const T*, const T*)) \ 689 | { \ 690 | return zvec_bsearch_##Name(v, k, cmp); \ 691 | } \ 692 | \ 693 | static inline T* zvec_lower_bound_dispatch(zvec_##Name *v, const T* k, \ 694 | int (*cmp)(const T*, const T*)) \ 695 | { \ 696 | return zvec_lower_bound_##Name(v, k, cmp); \ 697 | } 698 | #else 699 | // C implementation: uses realloc / memmove / free. 700 | #define ZVEC_IMPL_ALLOC(T, Name) \ 701 | static inline int zvec_reserve_##Name(zvec_##Name *v, size_t new_cap) \ 702 | { \ 703 | if (new_cap <= v->capacity) \ 704 | { \ 705 | return Z_OK; \ 706 | } \ 707 | T* new_data = (T*)ZVEC_REALLOC(v->data, new_cap * sizeof(T)); \ 708 | if (!new_data) \ 709 | { \ 710 | return Z_ENOMEM; \ 711 | } \ 712 | v->data = new_data; \ 713 | v->capacity = new_cap; \ 714 | return Z_OK; \ 715 | } \ 716 | \ 717 | static inline void zvec_free_##Name(zvec_##Name *v) \ 718 | { \ 719 | ZVEC_FREE(v->data); \ 720 | memset(v, 0, sizeof(zvec_##Name)); \ 721 | } \ 722 | \ 723 | static inline void zvec_remove_##Name(zvec_##Name *v, size_t index) \ 724 | { \ 725 | if (index >= v->length) \ 726 | { \ 727 | return; \ 728 | } \ 729 | memmove(&v->data[index], &v->data[index + 1], (v->length - index - 1) * sizeof(T)); \ 730 | v->length--; \ 731 | } \ 732 | \ 733 | static inline void zvec_shrink_to_fit_##Name(zvec_##Name *v) \ 734 | { \ 735 | if (v->length == v->capacity) \ 736 | { \ 737 | return; \ 738 | } \ 739 | if (0 == v->length) \ 740 | { \ 741 | zvec_free_##Name(v); \ 742 | return; \ 743 | } \ 744 | T* new_data = (T*)ZVEC_REALLOC(v->data, v->length * sizeof(T)); \ 745 | if (new_data) \ 746 | { \ 747 | v->data = new_data; \ 748 | v->capacity = v->length; \ 749 | } \ 750 | } 751 | 752 | # define ZVEC_CPP_DISPATCH_IMPL(T, Name) // Empty in C. 753 | #endif 754 | 755 | /* 756 | * ZVEC_GENERATE_IMPL(T, Name) 757 | * 758 | * Primary generation macro. 759 | * 760 | * Use manually via: 761 | * #define REGISTER_ZVEC_TYPES(X) \ 762 | * X(int, Int) \ 763 | * X(float, Float) \ 764 | * X(MyType, MyType) 765 | * #include "zvec.h" 766 | * 767 | * This creates: 768 | * • struct zvec_Int / zvec_Float, etc. 769 | * • All functions: zvec_push_Int, zvec_reserve_Float, etc. 770 | * • Full _Generic dispatch. 771 | * • C++ traits specialization for z_vec::vector 772 | * 773 | * Fast path: returns int (Z_OK / Z_ENOMEM), asserts on logic errors. 774 | * Safe path (when zerror.h present): returns zres / zresult. 775 | */ 776 | #define ZVEC_GENERATE_IMPL(T, Name) \ 777 | \ 778 | typedef T zvec_T_##Name; \ 779 | \ 780 | typedef struct \ 781 | { \ 782 | T *data; \ 783 | size_t length; \ 784 | size_t capacity; \ 785 | } zvec_##Name; \ 786 | \ 787 | /* Forward declaration for C++ allocators to see. */ \ 788 | static inline int zvec_reserve_##Name(zvec_##Name *v, size_t new_cap); \ 789 | \ 790 | ZVEC_IMPL_ALLOC(T, Name) \ 791 | \ 792 | static inline zvec_##Name zvec_init_capacity_##Name(size_t cap) \ 793 | { \ 794 | zvec_##Name v; \ 795 | memset(&v, 0, sizeof(zvec_##Name)); \ 796 | if (cap > 0) \ 797 | { \ 798 | zvec_reserve_##Name(&v, cap); \ 799 | } \ 800 | return v; \ 801 | } \ 802 | \ 803 | static inline zvec_##Name zvec_from_array_##Name(const T *arr, size_t count) \ 804 | { \ 805 | zvec_##Name v = zvec_init_capacity_##Name(count); \ 806 | if (v.data) \ 807 | { \ 808 | size_t i; \ 809 | for(i = 0; ilength; \ 821 | } \ 822 | \ 823 | static inline T *zvec_push_slot_##Name(zvec_##Name *v) \ 824 | { \ 825 | if (v->length >= v->capacity) \ 826 | { \ 827 | size_t new_cap = Z_GROWTH_FACTOR(v->capacity); \ 828 | if (Z_OK != zvec_reserve_##Name(v, new_cap)) \ 829 | { \ 830 | return NULL; \ 831 | } \ 832 | } \ 833 | return &v->data[v->length++]; \ 834 | } \ 835 | \ 836 | static inline int zvec_push_##Name(zvec_##Name *v, T value) \ 837 | { \ 838 | T *slot = zvec_push_slot_##Name(v); \ 839 | if (!slot) \ 840 | { \ 841 | return Z_ENOMEM; \ 842 | } \ 843 | *slot = value; \ 844 | return Z_OK; \ 845 | } \ 846 | \ 847 | static inline int zvec_extend_##Name(zvec_##Name *v, const T *items, size_t count) \ 848 | { \ 849 | if (v->length + count > v->capacity) \ 850 | { \ 851 | size_t new_cap = v->capacity ? v->capacity : Z_GROWTH_FACTOR(0); \ 852 | while (new_cap < v->length + count) \ 853 | { \ 854 | new_cap = Z_GROWTH_FACTOR(new_cap); \ 855 | } \ 856 | if (Z_OK != zvec_reserve_##Name(v, new_cap)) \ 857 | { \ 858 | return Z_ENOMEM; \ 859 | } \ 860 | } \ 861 | size_t i; \ 862 | for( i = 0; idata[v->length + i] = items[i]; \ 865 | } \ 866 | v->length += count; \ 867 | return Z_OK; \ 868 | } \ 869 | \ 870 | static inline void zvec_pop_##Name(zvec_##Name *v) \ 871 | { \ 872 | assert(v->length > 0 && "Popping empty vector"); \ 873 | v->length--; \ 874 | } \ 875 | \ 876 | static inline T zvec_pop_get_##Name(zvec_##Name *v) \ 877 | { \ 878 | assert(v->length > 0 && "Vector is empty"); \ 879 | return v->data[--v->length]; \ 880 | } \ 881 | \ 882 | static inline T *zvec_at_##Name(zvec_##Name *v, size_t index) \ 883 | { \ 884 | return (index < v->length) ? &v->data[index] : NULL; \ 885 | } \ 886 | \ 887 | static inline T *zvec_data_##Name(zvec_##Name *v) \ 888 | { \ 889 | return v->data; \ 890 | } \ 891 | \ 892 | static inline T *zvec_last_##Name(zvec_##Name *v) \ 893 | { \ 894 | return (v->length > 0) ? &v->data[v->length - 1] : NULL; \ 895 | } \ 896 | \ 897 | static inline void zvec_swap_remove_##Name(zvec_##Name *v, size_t index) \ 898 | { \ 899 | if (index >= v->length) return; \ 900 | v->data[index] = v->data[--v->length]; \ 901 | } \ 902 | \ 903 | static inline void zvec_clear_##Name(zvec_##Name *v) \ 904 | { \ 905 | v->length = 0; \ 906 | } \ 907 | \ 908 | static inline void zvec_reverse_##Name(zvec_##Name *v) \ 909 | { \ 910 | if (v->length < 2) \ 911 | { \ 912 | return; \ 913 | } \ 914 | size_t i = 0; \ 915 | size_t j = v->length - 1; \ 916 | while (i < j) \ 917 | { \ 918 | T temp = v->data[i]; \ 919 | v->data[i] = v->data[j]; \ 920 | v->data[j] = temp; \ 921 | i++; \ 922 | j--; \ 923 | } \ 924 | } \ 925 | \ 926 | static inline void zvec_sort_##Name(zvec_##Name *v, \ 927 | int (*compar)(const T *, const T *)) \ 928 | { \ 929 | if (v->length > 1) \ 930 | { \ 931 | qsort(v->data, v->length, sizeof(T), \ 932 | (int(*)(const void *, const void *))compar); \ 933 | } \ 934 | } \ 935 | \ 936 | static inline T *zvec_bsearch_##Name(zvec_##Name *v, const T *key, \ 937 | int (*compar)(const T *, const T *)) \ 938 | { \ 939 | if (0 == v->length) \ 940 | { \ 941 | return NULL; \ 942 | } \ 943 | return (T *)bsearch(key, v->data, v->length, sizeof(T), \ 944 | (int(*)(const void *, const void *))compar); \ 945 | } \ 946 | \ 947 | static inline T *zvec_lower_bound_##Name(zvec_##Name *v, const T *key, \ 948 | int (*compar)(const T *, const T *)) \ 949 | { \ 950 | size_t l = 0; \ 951 | size_t r = v->length; \ 952 | while (l < r) \ 953 | { \ 954 | size_t mid = l + (r - l) / 2; \ 955 | if (compar((const T *)&v->data[mid], key) < 0) \ 956 | { \ 957 | l = mid + 1; \ 958 | } \ 959 | else \ 960 | { \ 961 | r = mid; \ 962 | } \ 963 | } \ 964 | return (l < v->length) ? &v->data[l] : NULL; \ 965 | } \ 966 | \ 967 | /* Inject safe API. */ \ 968 | ZVEC_GEN_SAFE_IMPL(T, Name) 969 | 970 | // Dispatch table entries for _Generic. 971 | #define PUSH_ENTRY(T, Name) zvec_##Name *: zvec_push_##Name, 972 | #define PUSH_SLOT_ENTRY(T, Name) zvec_##Name *: zvec_push_slot_##Name, 973 | #define EXTEND_ENTRY(T, Name) zvec_##Name *: zvec_extend_##Name, 974 | #define RESERVE_ENTRY(T, Name) zvec_##Name *: zvec_reserve_##Name, 975 | #define IS_EMPTY_ENTRY(T, Name) zvec_##Name *: zvec_is_empty_##Name, 976 | #define AT_ENTRY(T, Name) zvec_##Name *: zvec_at_##Name, 977 | #define DATA_ENTRY(T, Name) zvec_##Name *: zvec_data_##Name, 978 | #define LAST_ENTRY(T, Name) zvec_##Name *: zvec_last_##Name, 979 | #define FREE_ENTRY(T, Name) zvec_##Name *: zvec_free_##Name, 980 | #define POP_ENTRY(T, Name) zvec_##Name *: zvec_pop_##Name, 981 | #define POP_GET_ENTRY(T, Name) zvec_##Name *: zvec_pop_get_##Name, 982 | #define SHRINK_ENTRY(T, Name) zvec_##Name *: zvec_shrink_to_fit_##Name, 983 | #define REMOVE_ENTRY(T, Name) zvec_##Name *: zvec_remove_##Name, 984 | #define SWAP_REM_ENTRY(T, Name) zvec_##Name *: zvec_swap_remove_##Name, 985 | #define CLEAR_ENTRY(T, Name) zvec_##Name *: zvec_clear_##Name, 986 | #define REVERSE_ENTRY(T, Name) zvec_##Name *: zvec_reverse_##Name, 987 | #define SORT_ENTRY(T, Name) zvec_##Name *: zvec_sort_##Name, 988 | #define BSEARCH_ENTRY(T, Name) zvec_##Name *: zvec_bsearch_##Name, 989 | #define LOWER_BOUND_ENTRY(T, Name) zvec_##Name *: zvec_lower_bound_##Name, 990 | 991 | #if Z_HAS_ZERROR 992 | # define RESERVE_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_reserve_safe_##Name, 993 | # define PUSH_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_push_safe_##Name, 994 | # define POP_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_pop_safe_##Name, 995 | # define AT_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_at_safe_##Name, 996 | # define LAST_SAFE_ENTRY(T, Name) zvec_##Name *: zvec_last_safe_##Name, 997 | #endif 998 | 999 | #ifndef REGISTER_ZVEC_TYPES 1000 | # if defined(__has_include) && __has_include("z_registry.h") 1001 | # include "z_registry.h" 1002 | # endif 1003 | #endif 1004 | 1005 | #ifndef REGISTER_ZVEC_TYPES 1006 | # define REGISTER_ZVEC_TYPES(X) 1007 | #endif 1008 | 1009 | #ifndef Z_AUTOGEN_VECS 1010 | # define Z_AUTOGEN_VECS(X) 1011 | #endif 1012 | 1013 | #define Z_ALL_VECS(X) \ 1014 | Z_AUTOGEN_VECS(X) \ 1015 | REGISTER_ZVEC_TYPES(X) 1016 | 1017 | Z_ALL_VECS(ZVEC_GENERATE_IMPL) 1018 | 1019 | // Public convenience macros. 1020 | 1021 | #define zvec_from(Name, ...) \ 1022 | zvec_from_array_##Name((zvec_T_##Name[]){__VA_ARGS__}, \ 1023 | sizeof((zvec_T_##Name[]){__VA_ARGS__}) / sizeof(zvec_T_##Name)) 1024 | 1025 | #define zvec_init(Name) zvec_init_capacity_##Name(0) 1026 | #define zvec_init_with_cap(Name, cap) zvec_init_capacity_##Name(cap) 1027 | 1028 | #if Z_HAS_CLEANUP 1029 | # define zvec_autofree(Name) Z_CLEANUP(zvec_free_##Name) zvec_##Name 1030 | #endif 1031 | 1032 | // Generic dispatch using _Generic. 1033 | 1034 | #ifdef __cplusplus 1035 | // C++ Overload Dispatch 1036 | # define zvec_push(v, val) zvec_push_dispatch(v, val) 1037 | # define zvec_push_slot(v) zvec_push_slot_dispatch(v) 1038 | # define zvec_extend(v, arr, count) zvec_extend_dispatch(v, arr, count) 1039 | # define zvec_reserve(v, cap) zvec_reserve_dispatch(v, cap) 1040 | # define zvec_is_empty(v) zvec_is_empty_dispatch(v) 1041 | # define zvec_at(v, idx) zvec_at_dispatch(v, idx) 1042 | # define zvec_data(v) zvec_data_dispatch(v) 1043 | # define zvec_last(v) zvec_last_dispatch(v) 1044 | # define zvec_free(v) zvec_free_dispatch(v) 1045 | # define zvec_pop(v) zvec_pop_dispatch(v) 1046 | # define zvec_pop_get(v) zvec_pop_get_dispatch(v) 1047 | # define zvec_shrink_to_fit(v) zvec_shrink_to_fit_dispatch(v) 1048 | # define zvec_remove(v, i) zvec_remove_dispatch(v, i) 1049 | # define zvec_swap_remove(v, i) zvec_swap_remove_dispatch(v, i) 1050 | # define zvec_clear(v) zvec_clear_dispatch(v) 1051 | # define zvec_reverse(v) zvec_reverse_dispatch(v) 1052 | # define zvec_sort(v, cmp) zvec_sort_dispatch(v, cmp) 1053 | # define zvec_bsearch(v, k, c) zvec_bsearch_dispatch(v, k, c) 1054 | # define zvec_lower_bound(v, k, c) zvec_lower_bound_dispatch(v, k, c) 1055 | #else 1056 | // C _Generic Dispatch 1057 | # define zvec_push(v, val) _Generic((v), Z_ALL_VECS(PUSH_ENTRY) default: 0)(v, val) 1058 | # define zvec_push_slot(v) _Generic((v), Z_ALL_VECS(PUSH_SLOT_ENTRY) default: (void *)0)(v) 1059 | # define zvec_extend(v, arr, count) _Generic((v), Z_ALL_VECS(EXTEND_ENTRY) default: 0)(v, arr, count) 1060 | # define zvec_reserve(v, cap) _Generic((v), Z_ALL_VECS(RESERVE_ENTRY) default: 0)(v, cap) 1061 | # define zvec_is_empty(v) _Generic((v), Z_ALL_VECS(IS_EMPTY_ENTRY) default: 0)(v) 1062 | # define zvec_at(v, idx) _Generic((v), Z_ALL_VECS(AT_ENTRY) default: (void *)0)(v, idx) 1063 | # define zvec_data(v) _Generic((v), Z_ALL_VECS(DATA_ENTRY) default: (void *)0)(v) 1064 | # define zvec_last(v) _Generic((v), Z_ALL_VECS(LAST_ENTRY) default: (void *)0)(v) 1065 | # define zvec_free(v) _Generic((v), Z_ALL_VECS(FREE_ENTRY) default: (void)0)(v) 1066 | # define zvec_pop(v) _Generic((v), Z_ALL_VECS(POP_ENTRY) default: (void)0)(v) 1067 | # define zvec_pop_get(v) _Generic((v), Z_ALL_VECS(POP_GET_ENTRY) default: (void)0)(v) 1068 | # define zvec_shrink_to_fit(v) _Generic((v), Z_ALL_VECS(SHRINK_ENTRY) default: (void)0)(v) 1069 | # define zvec_remove(v, i) _Generic((v), Z_ALL_VECS(REMOVE_ENTRY) default: (void)0)(v, i) 1070 | # define zvec_swap_remove(v, i) _Generic((v), Z_ALL_VECS(SWAP_REM_ENTRY) default: (void)0)(v, i) 1071 | # define zvec_clear(v) _Generic((v), Z_ALL_VECS(CLEAR_ENTRY) default: (void)0)(v) 1072 | # define zvec_reverse(v) _Generic((v), Z_ALL_VECS(REVERSE_ENTRY) default: (void)0)(v) 1073 | # define zvec_sort(v, cmp) _Generic((v), Z_ALL_VECS(SORT_ENTRY) default: (void)0)(v, cmp) 1074 | # define zvec_bsearch(v, k, c) _Generic((v), Z_ALL_VECS(BSEARCH_ENTRY) default: (void *)0)(v, k, c) 1075 | # define zvec_lower_bound(v, k, c) _Generic((v), Z_ALL_VECS(LOWER_BOUND_ENTRY) default: (void *)0)(v, k, c) 1076 | #endif 1077 | 1078 | /* * Explicit declaration macro (portable C99) 1079 | * Usage: zvec_foreach_decl(Int, &vec, it) { ... } 1080 | */ 1081 | #define zvec_foreach_decl(Name, v, iter) \ 1082 | for (zvec_T_##Name *iter = (v)->data; \ 1083 | iter < (v)->data + (v)->length; \ 1084 | ++iter) 1085 | 1086 | // Smart iteration helpers (auto-inference). 1087 | #if defined(__GNUC__) || defined(__clang__) 1088 | 1089 | #define zvec_foreach(v, iter) \ 1090 | for (__typeof__((v)->data) iter = (v)->data; \ 1091 | iter < (v)->data + (v)->length; \ 1092 | ++iter) 1093 | 1094 | #else 1095 | 1096 | /* Standard C fallback: User must declare 'iter' before loop. 1097 | * Usage: int *it; zvec_foreach(&vec, it) { ... } 1098 | */ 1099 | #define zvec_foreach(v, iter) \ 1100 | for ((iter) = (v)->data; \ 1101 | (iter) < (v)->data + (v)->length; \ 1102 | ++(iter)) 1103 | 1104 | #endif 1105 | 1106 | // Safe API dispatch (zerror.h required). 1107 | #if Z_HAS_ZERROR && !defined(__cplusplus) 1108 | static inline zres zres_err_dummy(void *v, ...) 1109 | { 1110 | (void)v; 1111 | return zres_err(zerr_create(-1, "Unknown vector type")); 1112 | } 1113 | 1114 | # define zvec_reserve_safe(v, cap) \ 1115 | _Generic((v), Z_ALL_VECS(RESERVE_SAFE_ENTRY) default: zres_err_dummy)(v, cap, __FILE__, __LINE__, __func__) 1116 | 1117 | # define zvec_push_safe(v, val) \ 1118 | _Generic((v), Z_ALL_VECS(PUSH_SAFE_ENTRY) default: zres_err_dummy)(v, val, __FILE__, __LINE__, __func__) 1119 | 1120 | # define zvec_pop_safe(v) \ 1121 | _Generic((v), Z_ALL_VECS(POP_SAFE_ENTRY) default: zres_err_dummy)(v, __FILE__, __LINE__, __func__) 1122 | 1123 | # define zvec_at_safe(v, i) \ 1124 | _Generic((v), Z_ALL_VECS(AT_SAFE_ENTRY) default: zres_err_dummy)(v, i, __FILE__, __LINE__, __func__) 1125 | 1126 | # define zvec_last_safe(v) \ 1127 | _Generic((v), Z_ALL_VECS(LAST_SAFE_ENTRY) default: zres_err_dummy)(v, __FILE__, __LINE__, __func__) 1128 | #endif 1129 | 1130 | // Optional short names (never enabled by default). 1131 | #ifdef ZVEC_SHORT_NAMES 1132 | # define vec(Name) zvec_##Name 1133 | # define vec_init zvec_init 1134 | # define vec_init_with_cap zvec_init_with_cap 1135 | # define vec_from zvec_from 1136 | # define vec_autofree zvec_autofree 1137 | # define vec_push zvec_push 1138 | # define vec_push_slot zvec_push_slot 1139 | # define vec_extend zvec_extend 1140 | # define vec_reserve zvec_reserve 1141 | # define vec_is_empty zvec_is_empty 1142 | # define vec_at zvec_at 1143 | # define vec_data zvec_data 1144 | # define vec_last zvec_last 1145 | # define vec_free zvec_free 1146 | # define vec_pop zvec_pop 1147 | # define vec_pop_get zvec_pop_get 1148 | # define vec_shrink_to_fit zvec_shrink_to_fit 1149 | # define vec_remove zvec_remove 1150 | # define vec_swap_remove zvec_swap_remove 1151 | # define vec_clear zvec_clear 1152 | # define vec_reverse zvec_reverse 1153 | # define vec_sort zvec_sort 1154 | # define vec_bsearch zvec_bsearch 1155 | # define vec_lower_bound zvec_lower_bound 1156 | # define vec_foreach zvec_foreach 1157 | # if Z_HAS_ZERROR && !defined(__cplusplus) 1158 | # define vec_reserve_safe zvec_reserve_safe 1159 | # define vec_push_safe zvec_push_safe 1160 | # define vec_pop_safe zvec_pop_safe 1161 | # define vec_at_safe zvec_at_safe 1162 | # define vec_last_safe zvec_last_safe 1163 | # endif 1164 | #endif 1165 | 1166 | #ifdef __cplusplus 1167 | } // extern "C" 1168 | 1169 | Z_ALL_VECS(ZVEC_CPP_DISPATCH_IMPL) 1170 | 1171 | namespace z_vec 1172 | { 1173 | #define ZVEC_CPP_TRAITS(T, Name) \ 1174 | template <> struct traits \ 1175 | { \ 1176 | using c_type = ::zvec_##Name; \ 1177 | static inline void init(c_type &v) \ 1178 | { \ 1179 | v = ::zvec_init_capacity_##Name(0); \ 1180 | } \ 1181 | \ 1182 | static inline void init_cap(c_type &v, size_t c) \ 1183 | { \ 1184 | v = ::zvec_init_capacity_##Name(c); \ 1185 | } \ 1186 | \ 1187 | static inline void free(c_type &v) \ 1188 | { \ 1189 | ::zvec_free_##Name(&v); \ 1190 | } \ 1191 | \ 1192 | static inline int push(c_type &v, T val) \ 1193 | { \ 1194 | return ::zvec_push_##Name(&v, val); \ 1195 | } \ 1196 | \ 1197 | static inline int extend(c_type &v, const T *arr, size_t n) \ 1198 | { \ 1199 | return ::zvec_extend_##Name(&v, arr, n); \ 1200 | } \ 1201 | \ 1202 | static inline int reserve(c_type &v, size_t n) \ 1203 | { \ 1204 | return ::zvec_reserve_##Name(&v, n); \ 1205 | } \ 1206 | \ 1207 | static inline void pop(c_type &v) \ 1208 | { \ 1209 | ::zvec_pop_##Name(&v); \ 1210 | } \ 1211 | \ 1212 | static inline T pop_get(c_type &v) \ 1213 | { \ 1214 | return ::zvec_pop_get_##Name(&v); \ 1215 | } \ 1216 | \ 1217 | static inline void remove(c_type &v, size_t i) \ 1218 | { \ 1219 | ::zvec_remove_##Name(&v, i); \ 1220 | } \ 1221 | \ 1222 | static inline void swap_remove(c_type &v, size_t i) \ 1223 | { \ 1224 | ::zvec_swap_remove_##Name(&v, i); \ 1225 | } \ 1226 | \ 1227 | static inline void clear(c_type &v) \ 1228 | { \ 1229 | ::zvec_clear_##Name(&v); \ 1230 | } \ 1231 | \ 1232 | static inline void shrink(c_type &v) \ 1233 | { \ 1234 | ::zvec_shrink_to_fit_##Name(&v); \ 1235 | } \ 1236 | \ 1237 | static inline void reverse(c_type &v) \ 1238 | { \ 1239 | ::zvec_reverse_##Name(&v); \ 1240 | } \ 1241 | }; 1242 | 1243 | Z_ALL_VECS(ZVEC_CPP_TRAITS) 1244 | } 1245 | #endif // __cplusplus 1246 | 1247 | #endif // ZVEC_H 1248 | --------------------------------------------------------------------------------