diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index fdc48d5..0000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/BUGS.md b/BUGS.md
deleted file mode 100644
index 4f8c5d5..0000000
--- a/BUGS.md
+++ /dev/null
@@ -1,270 +0,0 @@
-# libvec bug tracker
-
-**Pass 12** — verified **2026-10-12** — `char.c` @ 957 lines · `char.h` @ 108
-
-| Open | S1 | S2 | S3 | C | DECIDE | Fixed |
-|:----:|:--:|:--:|:--:|:-:|:------:|:-----:|
-| **42** | 8 | 15 | 7 | 12 | 0 | 63 |
-
-`S1` memory safety · `S2` wrong result / broken contract · `S3` edge case · `C` cleanup · `DECIDE` open design question
-
-> **Line numbers are the only field that drifts.** Re-verify before trusting them.
-
----
-
-## Contents
-
-- [Triage — the 8 open S1s](#triage)
-- [Findings](#findings)
- - [Core storage](#core-storage)
- - [Validation & accessors](#validation--accessors)
- - [Algorithms](#algorithms)
- - [Support](#support)
-- [Fixed](#fixed)
-- [ID map](#id-map)
-
----
-
-
-
-## Triage — the 8 open S1s
-
-In suggested fixing order.
-
-| # | ID | Location | Summary |
-|:-:|:---|:---------|:--------|
-| 1 | `IV-5` | char.c:40-44 | `__null_check`'s NULL-`status` branch derefs the very NULL it just tested, and seven call sites pass the caller's `err` through here → `SEGV` at 42. **ASan Pass 12: SEGV in `__null_check`** |
-| 2 | `FB-1` | char.c:457-462, 475-480 | `front`/`back` guard inverted: populated vectors return 0 + `ERR_OUT_OF_BOUNDS`; drained vectors fall through to `*nullptr` → SEGV at 462/480. `back` probes index 0 |
-| 3 | `IN-10` | char.c:886-893 | amount-insert never validates: guard at 887 reads a fresh local (always 0), NULL `ptr` derefs at 893 → SEGV |
-| 4 | `ER-4` | char.c:541-542 | range-erase zeroing `memset` length is the whole `_internal_size`, not `diff`, so it writes past the buffer → `heap-buffer-overflow` WRITE at 541 |
-| 5 | `RZ-10` | char.c:626-629, 712-715 | resize-shrink `memset` length is the whole old `_internal_size`, not `old - new` → `heap-buffer-overflow` WRITE at 628/714 |
-| 6 | `RZ-11` | char.c:630-634, 716-720 | resize-growth `memset` length is `_internal_arr[size]` (an element value) instead of `size - _internal_size`; reads one past the block when `size == capacity` → `heap-buffer-overflow` READ at 633/719 |
-| 7 | `RS-1` | char.c:264-269 | truncation zeroed through the post-realloc pointer: `memset(&arr[capacity], 0, size - capacity)` (267) writes past the shrunk block → `heap-buffer-overflow` WRITE at 267 |
-| 8 | `DL-2` | char.h:8-14 | no ownership marker, by-value struct copy double-frees |
-
----
-
-
-
-## Findings
-
-
-
-### Core storage
-
-#### `_vec_char_push_back` / `_vec_char_pop_back` — char.c:141, 202
-
-*1 S2*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `PB-9` | S2 | char.c:161-173 vs 242-254 vs 839-853 | three blank-materialize paths, no shared shape. `push_back`: `malloc(1)`, `capacity=1`, `size=0`, writes `arr[0]`. `reserve`: `calloc(capacity)` and commits `capacity`. `insert` one-arg: `malloc(1)`, `capacity=1`, `size=1`, writes `arr[0]`. Same input state, three allocations, three struct results; `insert` and `resize` disagree with `push_back` on which blank states are accepted |
-
-#### `_vec_char_cpy` — char.c:103 — *Clear*
-
-#### `_vec_char_reserve` — char.c:221
-
-*1 S1*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `RS-1` | S1 | char.c:264-269 | `ptr->_internal_arr = res` (264) runs before the truncation, so the discarded tail is zeroed through the NEW pointer — but `realloc` already shrunk the block to `capacity` bytes, and `memset(&ptr->_internal_arr[capacity], 0, ptr->_internal_size - capacity)` (267-268) writes past it. **ASan Pass 12: `heap-buffer-overflow` WRITE at 267** — push 4, `reserve(&v, 2)`. The tail to zero no longer exists after a shrinking realloc: the `memset` must run on the old buffer before `realloc`, or be dropped — spare slots are uninitialized by contract |
-
-#### `_vec_char_shrink_to_fit` — char.c:277 — *Clear*
-
-#### `_vec_char_swap` — char.c:295 — *Clear*
-
-#### `_vec_char_delete` — char.c:364
-
-*1 S1*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `DL-2` | S1 | char.h:8-14 | no ownership marker on the struct, so a by-value copy yields two owners of one buffer; each `delete` clears only its own struct's pointer, so the second free hits the first's freed block. **ASan Pass 12: `attempting double-free` at char.c:376** — `w = v; delete(&v); delete(&w)` |
-
-#### `_vec_char_clear` / `_vec_char_print_vec` — char.c:383, 89 — *Clear*
-
-
-
-### Validation & accessors
-
-#### `__null_check` / `__origin_override` — char.c:37, 69
-
-*1 S1*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `IV-5` | S1 | char.c:40-44 | the `status == nullptr` branch exists to catch a NULL `err_t*` but dereferences `status` on the next line (`status->flags = ...`, 42; `status->origin = ...`, 43). Seven call sites hand `__null_check` the caller's `err` verbatim (print_vec 92, pop_back 205, begin 425, end 438, front 451, back 469, empty 487), so any of those with a NULL `err` is a live null-deref. **ASan Pass 12: SEGV in `__null_check` at char.c:42.** Either return before the deref or drop the branch |
-
-#### `_vec_char_capacity` / `_vec_char_max_size` / `_vec_char_data` / `_vec_char_size` — char.c:338, 351, 312, 325
-
-*1 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `AC-3` | C | char.c:326-335 | new `size` accessor records its failure origin as `"CAPACITY"` (331), copied from `_vec_char_capacity`. It also takes a non-`const` `_VecCharInternal*` (326) while only reading, unlike its `const` siblings |
-
-#### `_vec_char_at` — char.c:400
-
-*1 S3 · 1 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `AT-2` | S3 | char.c:410-417 | the OOB path sets `err` (flags + origin AT) and returns `nullptr`, but still prints a raw line to **stdout** via `printf` (412-413), polluting program output and bypassing the error channel. The residual hazard moved to the callers: `front`/`back` dereference the `nullptr` (462, 480) → SEGV (FB-1) |
-| `AT-3` | C | char.c:400, 418 | `at()` returns a mutable `char*` into the buffer of a `const _VecCharInternal*` — const-laundering callers can write elements behind the API's back, bypassing `push_back`/`resize` bookkeeping; the pointer also invalidates on any realloc |
-
-#### `_vec_char_begin` / `_vec_char_end` — char.c:421, 434
-
-*1 S2*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `BE-1` | S2 | char.c:421-432, 434-445, 749-750, 799-800 | `begin` returns raw `status.flags` (bitmask 2/4) as an index on failure (429), and `end`'s `(size_t)(size - 1)` (444) is **reachable for a drained vector** — `size == 0` wraps to `SIZE_MAX` (harness Pass 12: end(drained) = 18446744073709551615, flags=0). Flags-as-index and SIZE_MAX-as-end are indistinguishable from real positions; `SIZE_MAX + 1` wraps to 0 at 749-750, 799-800, so `assign` into a drained destination erases `[0, 0)` and fails with `ERR_OUT_OF_BOUNDS` (AS-1) |
-
-#### `_vec_char_front` / `_vec_char_back` / `_vec_char_empty` — char.c:447, 465, 483
-
-*1 S1 · 1 S2*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `FB-1` | S1 | char.c:457-462, 475-480 | the guard meant to kill the drained SEGV is **inverted and probes the wrong index**. `at()` returns `nullptr` on failure, so `if (_vec_char_at(...) != nullptr)` fires for *valid* vectors: **`front`/`back` on a populated vector return 0 with `ERR_OUT_OF_BOUNDS`** (harness Pass 12: front('ab')=0/flags=16, back=0/flags=16 — expected 97/98). For a drained vector `at` returns nullptr, the condition is false, control falls through to the deref — `front` → `*_vec_char_at(ptr, 0, err)` (462), `back` → `*_vec_char_at(ptr, size - 1, err)` (480) — **SEGV** (ASan Pass 12: SEGV at 462 and 480). `back` also probes index 0 (475) instead of `size - 1`. Condition must be `== nullptr`, and `back` must probe the last index |
-| `AC-2` | S2 | char.c:483-498 | `empty()` still returns 0 in *both* directions: a drained vector takes the `size == 0` branch and `return SUCCESS` (493-496), a populated one falls through to `return status.flags`, also 0 (497) — so `if (empty(&v))` is never true for a valid vector. **Harness Pass 12: drained → 0/err 0, populated → 0/err 0** |
-
-
-
-### Algorithms
-
-#### `_vec_char_erase` (both overloads) — char.c:501, 520
-
-*1 S1 · 1 S2 · 1 S3 · 1 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `ER-4` | S1 | char.c:541-542 | the trailing-zero `memset` starts at `_internal_size - diff` but its length is `sizeof(char) * ptr->_internal_size` (the *whole* old size, though `_internal_size` is not decremented until 543), so it writes `[size - diff, 2*size - diff)` — past the block whenever more than `diff` elements remain. Should be `diff` bytes. **ASan Pass 12: `heap-buffer-overflow` WRITE at 541** — 10 elements in a 13-byte block, `erase(&v, 0, 1)` |
-| `ER-1` | S2 | char.c:532-537 | `erase` on an empty vector never no-ops: a drained vector passes the `__null_check` guard now, then the range check (`size < iter_end \|\| iter_end <= iter_start`) fires — `[0, 1)` because `0 < 1`, and even `[0, 0)` because `0 <= 0`. **Harness Pass 12: erase(v, 0, 1) on drained → err=16, origin ERASE** |
-| `ER-3` | S3 | char.c:511 | the single-arg overload silently returns on `iter >= size` with `err` untouched (harness Pass 12: erase index 99 → flags=0), while the range overload reports `ERR_OUT_OF_BOUNDS` for the same condition. A typo'd index is invisible to an err-driven caller |
-| `ER-2` | C | char.c:500, 519 | two stale `// TODO: Fix return value` comments remain (the second doubled as `// // TODO`) |
-
-#### `_vec_char_resize` (both overloads) — char.c:547, 639
-
-*2 S1 · 2 S2 · 2 S3 · 3 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `RZ-10` | S1 | char.c:626-629, 712-715 | shrink zeroing `memset(&arr[size], 0, ptr->_internal_size)` uses the *whole old* `_internal_size` as the length instead of `old - new`, so it writes past the block whenever `0 < size < old`. Should be `_internal_size - size` bytes. **ASan Pass 12: `heap-buffer-overflow` WRITE at 628** — 5 elements in a 6-byte block, `resize(&v, 2)` (also 714 for the 3-arg overload) |
-| `RZ-11` | S1 | char.c:630-634, 716-720 | growth fill `memset(&arr[_internal_size], 0, ptr->_internal_arr[size])` passes `_internal_arr[size]` — an *element value* (or 0xbe uninitialized) — as the byte count instead of `size - _internal_size`, and when `size == _internal_capacity` that read is one past the block. **ASan Pass 12: `heap-buffer-overflow` READ at 633** — 5 elements in a 6-byte block, `resize(&v, 6)` (also 719 for the 3-arg overload) |
-| `RZ-3` | S2 | char.c:573-596, 665-688 | the `max_size` save/restore (575/594, 667/686) is pure belt-and-braces now that `reserve` leaves `max_size` alone, and looks removable. Nothing documents that |
-| `RZ-1` | S2 | char.c:559-564, 651-656 | `size == _internal_size` returns `ERR_OUT_OF_BOUNDS` for a legitimate no-op; the code is also semantically wrong |
-| `RZ-4` | S3 | char.c:594-596 vs 686-688 | the 3-arg blank branch fills with `val`, the 2-arg with `0`. `data()` exposes the difference |
-| `RZ-2` | S3 | char.c:605, 695 | unguarded `tmpcp *= 2` wraps on overflow. Defensive |
-| `RZ-5` | C | char.c:584-589, 607-611, 618-623, 676-681, 699-703 | dead post-`reserve` capacity checks in the blank branches (584, 676) and the 2-arg growth branch (618); the 3-arg growth branch has no check at all, relying on `reserve` to be exact |
-| `RZ-6` | C | char.c:547-637 vs 639-723 | two ~90-line near-identical bodies, with the growth blocks copy-pasted between them |
-| `RZ-7` | C | char.c:590-593, 682-685 | the blank-branch fill loops should be `memset` |
-
-#### `_vec_char_assign` (both overloads) — char.c:725, 783
-
-*4 S2 · 1 S3 · 1 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `AS-1` | S2 | char.c:730-735, 749-750, 799-800 | fails on any empty destination. A **blank** destination trips the `__null_check` guard (730-735) → err=4, origin ASSIGN. A **drained** one passes the guard, then `end()` returns `SIZE_MAX` (BE-1) and `end + 1` wraps to 0 (749, 799), so `erase(0, 0)` fails the range check → err=16. Two paths, same refusal |
-| `AS-2` | S2 | char.c:749-778, 799-823 | not atomic: `erase` → `reserve` → `push_back` loop. Reserve failure leaves the destination wiped; a `push_back` failure mid-loop leaves it partially filled. Still no rollback |
-| `AS-3` | S2 | char.c:757, 807 | no `> _internal_max_size` guard on the assign count |
-| `AS-7` | S2 | char.c:764-770 | the `at()` guard in assign1 is **inverted**: `at()` returns `nullptr` on failure, so the `!= nullptr` branch fires for *valid* iterators — assign1 fails with `ERR_OUT_OF_BOUNDS` on the first element of **every non-empty source**, after erase already wiped the destination (harness Pass 12: dest `{x,y}` ← src `{a,b}` → flags=16, size=0). Condition must be `== nullptr` |
-| `AS-9` | S3 | char.c:788-792 | the null guard in the amount overload has **no `return`**, unlike assign1 — control falls through with `err` already flagged. Masked today only because the `erase` at 799 rejects the same state downstream |
-| `AS-6` | C | char.c:725-781 vs 783-825 | near-duplicate overloads differing only in the value source |
-
-#### `_vec_char_insert` (all three overloads) — char.c:827, 882, 918
-
-*1 S1 · 2 S2 · 2 S3 · 2 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `IN-10` | S1 | char.c:886-893 | the amount overload never calls `__null_check`: the guard at 887-892 tests a freshly-initialized local `status`, which is always 0, so it can never fire; `ptr` is then dereferenced raw at 893. Every other entry point validates first. **ASan Pass 12: SEGV at char.c:893** — `_vec_char_insert(nullptr, 0, 2, 'x', &e)` |
-| `IN-1` | S2 | char.c:932-938 | inverted range check: `iter_end > iter_start` rejects every non-empty range with `ERR_OUT_OF_BOUNDS` and accepts only empty ranges, which then silently do nothing (loop at 945 never runs). Valid insert-range never inserts. **Harness Pass 12: dest `{a,b}`, src `{Z}`, insert at 1 range [0,1) → err=16, size stays 2** |
-| `IN-4` | S2 | char.c:854-859, 884-893 | no `max_size` pre-check in the amount overload: the loop pushes until one-arg insert trips `size+1 > max_size` (854) and then returns, but everything already inserted stays — an oversized `amount` half-inserts and leaves the vector half-modified |
-| `IN-5` | S3 | char.c:899-904 | `amount <= 0` on a `size_t` is always just `== 0` |
-| `IN-6` | S3 | char.c:905 | `iter + amount` can overflow `size_t`, wrapping the loop bound and exiting early — a silent partial insert |
-| `IN-8` | C | char.c:945-955 | the loop reads `iterator->_internal_arr[i]` raw (948) instead of a bounds-checked accessor. **Unreachable today**: IN-1's inversion rejects every non-empty range, so the body never runs. The `iter_end > iterator->_internal_size` clause at 932 does bound the read once IN-1 is fixed, so this stays a style finding |
-| `IN-9` | C | char.c:905-914 | O(amount²) loop of single inserts where one grow + `memmove` would do |
-
-
-
-### Support
-
-#### `utils.h` / `utils.c`
-
-*3 S2 · 1 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `UT-1` | S2 | utils.h:9 | `SIZE_MAX / sizeof(int)` is what the `char` vector uses as `_internal_max_size`, capping it at 1/4 of the usable address space |
-| `UT-6` | S2 | utils.c:14-16 | `vec_get_error_desc`'s default case is an expression statement — `"Unknown";` with no `return` — so an out-of-range code falls off the end of a non-void function: UB, and the caller printf's a garbage `char*`. Current call sites only pass constants, so it is one cast away |
-| `UT-7` | S2 | utils.c:22-35 | `vec_print_errs` prints `err.origin` only on the SUCCESS branch (24), where it is always NULL on an untouched `err_t` — `%s` of NULL, UB — and the failure branch (27-35) never prints origin at all. The root-cause feature surfaces exactly backwards |
-| `UT-4` | C | utils.h:7-9, 63-65 | `static const` in a header gives every TU its own copy; `ERR_SIZE_ZERO` message mentions `< 0` on a `size_t`; `LOG`/`DEBUG` are hardwired to stdout and single-arg; `find_len` is UB for pointers; `CAPACITY` (7) and `VEC_FAULT_BITS` (8) are now referenced by nothing in the tree |
-
-#### `char.h` — *Clear*
-
-#### Project
-
-*2 C*
-
-| ID | Sev | Location | Finding |
-|:---|:--:|:---------|:--------|
-| `PR-8` | C | char.c:72, 112 (and every guard) | no function checks `err` for NULL before the first error path derefs it; a NULL `err_t*` segfaults on the first failure. Now documented (char.c:27-30) — a cheap defensive check would still harden the API. IV-5 is the same hazard at the one site that *tries* to check |
-| `PR-2` | C | char.c:179, 500, 519 | mixed brace style (single-line `if` at 179 vs expanded blocks) and stale `TODO` comments at 500/519; `.clang-format` exists and is not run |
-
----
-
-
-
-## Fixed
-
-
-63 fixed IDs — no rows
-
-```
-PB-1 PB-2 PB-3 PB-4 PB-6 PB-7 PB-8 PB-14 PB-15 PB-16 PB-17 PB-18 PB-20 PB-21
-RS-2 RS-3 RS-4 RS-6 RS-7 RS-8
-IV-1 IV-3 IV-4
-CH-1 CH-3 CH-7
-CR-3 CR-4 CR-6 CR-7 CR-8 CR-10 CR-11
-SW-1 SW-2
-FB-2
-AC-1 DA-1
-AT-1
-DL-1 DL-3
-UT-2 UT-3 UT-5
-PR-1 PR-3 PR-4
-CL-1 CL-2
-RZ-8 RZ-9
-AS-4 AS-8
-ST-1 ST-2
-IN-2 IN-11 IN-12
-FX-2 FX-3 FX-4 FX-5
-BE-2
-```
-
-Closed by owner decision (not counted fixed): `CH-9` (leading `_` intended private), `PR-7` (main not the test harness), `CH-4` (header includes), `CH-5` (doc comments), `CH-8` (struct naming), `PR-5` (placeholder comments), `CH-2` (const on by-value params for LSP/clarity).
-
-
-
----
-
-
-
-## ID map
-
-| Prefix | Scope | Prefix | Scope |
-|:------:|:------|:------:|:------|
-| `PB-` | push_back, pop_back | `AT-` | at |
-| `RS-` | reserve | `FB-` | front, back |
-| `ST-` | shrink_to_fit | `BE-` | begin, end |
-| `CR-` | create → cpy | `SW-` | swap |
-| `AC-` | accessors | `CL-` | clear, print_vec |
-| `DA-` | data | `IV-` | is_valid → __null_check |
-| `DL-` | delete | `UT-` | utils.h, utils.c |
-| `ER-` | erase | `CH-` | char.h |
-| `RZ-` | resize | `PR-` | project |
-| `AS-` | assign | `FX-` | retired first-pass IDs |
-| `IN-` | insert | | |
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index caa9895..884db8e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,10 +9,20 @@ add_library(libvec STATIC
src/int.c
src/utils.c
src/float.c
- # src/string.c
+ src/string.c
# Add your other types here as you implement them:
)
+include(FetchContent)
+FetchContent_Declare(libstr
+ GIT_REPOSITORY https://git.moomancer.xyz/DarthMooMancer/libstr.git
+ GIT_TAG main
+ GIT_SHALLOW TRUE
+)
+FetchContent_MakeAvailable(libstr)
+
+target_link_libraries(libvec PRIVATE libstr)
+
target_include_directories(libvec
# PRIVATE: Internal headers under src/lib are only visible
# to files being compiled into libvec (char.c, utils.c, libvec.c).
diff --git a/include/libvec/string.h b/include/libvec/string.h
new file mode 100644
index 0000000..c0d49e0
--- /dev/null
+++ b/include/libvec/string.h
@@ -0,0 +1,115 @@
+#ifndef CHAR_H
+#define CHAR_H
+
+#include
+#include
+
+// Will add DOCS later
+
+typedef struct
+{
+ String* array;
+ size_t size;
+ size_t capacity;
+ size_t max_size;
+} vec_string;
+
+__attribute__((overloadable)) size_t
+__null_check(const vec_string* ptr, err_t* status);
+
+__attribute__((overloadable)) size_t
+__null_check(const char* ptr, err_t* status);
+
+void
+vec_string_print_vec(const vec_string* ptr, err_t* err);
+
+vec_string
+vec_string_cpy(const char* src, const size_t src_size, err_t* err);
+
+void
+vec_string_push_back(vec_string* ptr, const String val, err_t* err);
+
+void
+vec_string_pop_back(vec_string* ptr, err_t* err);
+
+void
+vec_string_reserve(vec_string* ptr, const size_t capacity, err_t* err);
+
+void
+vec_string_shrink_to_fit(vec_string* ptr, err_t* err);
+
+void
+vec_string_swap(vec_string* ptr_a, vec_string* ptr_b, err_t* err);
+
+const String*
+vec_string_data(const vec_string* ptr, err_t* err);
+
+size_t
+vec_string_size(const vec_string* ptr, err_t* err);
+
+size_t
+vec_string_capacity(const vec_string* ptr, err_t* err);
+
+size_t
+vec_string_max_size(const vec_string* ptr, err_t* err);
+
+void
+vec_string_delete(vec_string* ptr, err_t* err);
+
+void
+vec_string_clear(vec_string* ptr, err_t* err);
+
+String*
+vec_string_at(const vec_string* ptr, const size_t idx, err_t* err);
+
+size_t
+vec_string_begin(const vec_string* ptr, err_t* err);
+
+size_t
+vec_string_end(const vec_string* ptr, err_t* err);
+
+String
+vec_string_front(const vec_string* ptr, err_t* err);
+
+String
+vec_string_back(const vec_string* ptr, err_t* err);
+
+size_t
+vec_string_empty(const vec_string* ptr, err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_erase(vec_string* ptr, const size_t iter, err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_erase(vec_string* ptr, const size_t iter_start,
+ const size_t iter_end, err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_resize(vec_string* ptr, const size_t size, err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_resize(vec_string* ptr, const size_t size, const String val,
+ err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_assign(vec_string* ptr, const vec_string* iterator,
+ const size_t iter_start, const size_t iter_end, err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_assign(vec_string* ptr, const size_t amount, const String val,
+ err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_insert(vec_string* ptr, const size_t iter, const String val,
+ err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_insert(vec_string* ptr, const size_t iter, const size_t amount,
+ const String val, err_t* err);
+
+__attribute__((overloadable)) void
+vec_string_insert(vec_string* ptr, const vec_string* iterator,
+ const size_t iter, const size_t iter_start,
+ const size_t iter_end, err_t* err);
+
+#endif
diff --git a/src/char.c b/src/char.c
index 136916b..125da6c 100644
--- a/src/char.c
+++ b/src/char.c
@@ -681,7 +681,7 @@ vec_char_assign(vec_char* ptr, const vec_char* iterator,
err->flags |= ERR_OUT_OF_BOUNDS;
return;
}
- vec_char_erase(ptr, _vec_char_begin(ptr, &status),
+ vec_char_erase(ptr, vec_char_begin(ptr, &status),
vec_char_end(ptr, &status) + 1, &status);
if (status.flags != 0)
{
@@ -731,7 +731,7 @@ vec_char_assign(vec_char* ptr, const size_t amount, const char val, err_t* err)
err->flags |= ERR_SIZE_ZERO;
return;
}
- vec_char_erase(ptr, _vec_char_begin(ptr, &status),
+ vec_char_erase(ptr, vec_char_begin(ptr, &status),
vec_char_end(ptr, &status) + 1, &status);
if (status.flags != 0)
{
diff --git a/src/main.c b/src/main.c
index 07b627a..06f69e0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -6,9 +6,6 @@
*/
/*
* Types Wanted:
- * Char 8 Bits
- * Float 32 Bits with suffix of 'f'
- * Int 32 bits
* String 32 Bits with suffix of 's'
*/
diff --git a/src/string.c b/src/string.c
new file mode 100644
index 0000000..82c53ce
--- /dev/null
+++ b/src/string.c
@@ -0,0 +1,912 @@
+#include "libstr/string.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+__attribute__((overloadable)) size_t
+__null_check(const vec_string* ptr, err_t* status)
+{
+ if (status == nullptr)
+ {
+ return ERR_ERR_T_NULL;
+ }
+ if (ptr == nullptr)
+ {
+ status->flags |= ERR_VEC_NULL;
+ return ERR_VEC_NULL;
+ }
+ if (ptr->array == nullptr)
+ {
+ status->flags |= ERR_BUF_NULL;
+ }
+
+ return status->flags;
+}
+
+void
+vec_string_print_vec(const vec_string* ptr, err_t* err)
+{
+ if (__null_check(ptr, err) != 0)
+ {
+ return;
+ }
+ for (size_t i = 0; i < ptr->size; i++)
+ {
+ printf("%s ", ptr->array[i].data);
+ }
+ printf("\n");
+}
+
+vec_string
+vec_string_cpy(const char* src, const size_t src_size, err_t* err)
+{
+ vec_string self = VEC_INIT;
+ err_t status = ERR_T_INIT;
+
+ size_t null = __null_check(src, err);
+ if (null != 0)
+ {
+ if (null & ERR_ERR_T_NULL)
+ {
+ return self;
+ }
+ __origin_override(err, "CPY");
+ err->flags |= status.flags;
+ return self;
+ }
+ if (src_size == 0)
+ {
+ __origin_override(err, "CPY");
+ err->flags |= ERR_SIZE_ZERO;
+ err->flags |= status.flags;
+ return self;
+ }
+ if (src_size > self.max_size)
+ {
+ __origin_override(err, "CPY");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return self;
+ }
+ self.array = malloc(src_size * sizeof(String));
+ if (self.array == nullptr)
+ {
+ __origin_override(err, "CPY");
+ err->flags |= ERR_ALLOC_FAIL;
+ return self;
+ }
+ memcpy(self.array, src, src_size * sizeof(String));
+ self.size = src_size;
+ self.capacity = src_size;
+ return self;
+}
+
+void
+vec_string_push_back(vec_string* ptr, const String val, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ String* res;
+ __null_check(ptr, &status);
+ if ((status.flags & ERR_VEC_NULL) != 0)
+ {
+ __origin_override(err, "PUSH_BACK");
+ err->flags |= ERR_VEC_NULL;
+ return;
+ }
+
+ if (ptr->size + 1 > ptr->max_size)
+ {
+ __origin_override(err, "PUSH_BACK");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return;
+ }
+
+ if ((status.flags & ERR_BUF_NULL) != 0)
+ {
+ res = malloc(1 * sizeof(String));
+ if (res == nullptr)
+ {
+ __origin_override(err, "PUSH_BACK");
+ err->flags |= ERR_ALLOC_FAIL;
+ return;
+ }
+ ptr->array = res;
+ ptr->capacity = 1;
+ ptr->size = 0;
+ }
+
+ else if (ptr->size + 1 > ptr->capacity)
+ {
+ size_t dst_cap = (ptr->capacity / 2) + ptr->capacity;
+ if (dst_cap == ptr->capacity)
+ {
+ dst_cap++;
+ }
+ if (dst_cap > ptr->max_size)
+ {
+ dst_cap = ptr->max_size;
+ DEBUG(
+ "Capacity cannot be grown any further due "
+ "to hitting max size");
+ }
+ res = realloc(ptr->array, dst_cap * sizeof(String));
+ if (res == nullptr)
+ {
+ __origin_override(err, "PUSH_BACK");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return;
+ }
+ ptr->array = res;
+ ptr->capacity = dst_cap;
+ }
+ ptr->array[ptr->size] = val;
+ ptr->size++;
+ return;
+}
+
+void
+vec_string_pop_back(vec_string* ptr, err_t* err)
+{
+ if (__null_check(ptr, err) != 0)
+ {
+ __origin_override(err, "POP_BACK");
+ return;
+ }
+
+ if (ptr->size == 0)
+ {
+ __origin_override(err, "POP_BACK");
+ err->flags |= ERR_SIZE_ZERO;
+ return;
+ }
+
+ ptr->array[ptr->size - 1] = (String)STR_INIT;
+ ptr->size--;
+}
+
+void
+vec_string_reserve(vec_string* ptr, const size_t capacity, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ if ((status.flags & ERR_VEC_NULL) != 0)
+ {
+ __origin_override(err, "RESERVE");
+ err->flags |= ERR_VEC_NULL;
+ return;
+ }
+ }
+ if (ptr->max_size < capacity)
+ {
+ __origin_override(err, "RESERVE");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return;
+ }
+ if (capacity == 0)
+ {
+ __origin_override(err, "RESERVE");
+ err->flags |= ERR_SIZE_ZERO;
+ return;
+ }
+
+ String* res = realloc(ptr->array, capacity * sizeof(String));
+ if (res == nullptr)
+ {
+ __origin_override(err, "RESERVE");
+ err->flags |= ERR_ALLOC_FAIL;
+ return;
+ }
+ ptr->array = res;
+ ptr->capacity = capacity;
+ if (ptr->size > capacity)
+ {
+ ptr->size = capacity;
+ }
+ return;
+}
+
+void
+vec_string_shrink_to_fit(vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "SHRINK_TO_FIT");
+ err->flags |= status.flags;
+ return;
+ }
+ if (ptr->size == 0)
+ {
+ __origin_override(err, "SHRINK_TO_FIT");
+ err->flags |= ERR_SIZE_ZERO;
+ return;
+ }
+ vec_string_reserve(ptr, ptr->size, err);
+}
+
+void
+vec_string_swap(vec_string* ptr_a, vec_string* ptr_b, err_t* err)
+{
+ err_t status_1 = ERR_T_INIT, status_2 = ERR_T_INIT;
+ if ((__null_check(ptr_a, &status_1) & ERR_VEC_NULL) != 0 ||
+ (__null_check(ptr_b, &status_2) & ERR_VEC_NULL) != 0)
+ {
+ __origin_override(err, "SWAP");
+ err->flags |= ERR_VEC_NULL;
+ return;
+ }
+ vec_string self = *ptr_a;
+ *ptr_a = *ptr_b;
+ *ptr_b = self;
+ return;
+}
+
+const String*
+vec_string_data(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "DATA");
+ err->flags |= status.flags;
+ return nullptr;
+ }
+ return &ptr->array[0];
+}
+
+size_t
+vec_string_size(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "SIZE");
+ err->flags |= status.flags;
+ return 0;
+ }
+ return ptr->size;
+}
+
+size_t
+vec_string_capacity(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "CAPACITY");
+ err->flags |= status.flags;
+ return 0;
+ }
+ return ptr->capacity;
+}
+
+size_t
+vec_string_max_size(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "MAX_SIZE");
+ err->flags |= status.flags;
+ return 0;
+ }
+ return ptr->max_size;
+}
+
+void
+vec_string_delete(vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "DELETE");
+ err->flags |= status.flags;
+ return;
+ }
+ if (ptr->array != nullptr)
+ {
+ free(ptr->array);
+ ptr->array = nullptr;
+ }
+ ptr->size = 0;
+ ptr->capacity = 0;
+}
+
+void
+vec_string_clear(vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "CLEAR");
+ err->flags |= status.flags;
+ return;
+ }
+ if (ptr->size > 0)
+ {
+ memset(ptr->array, 0, ptr->size);
+ ptr->size = 0;
+ }
+}
+
+String*
+vec_string_at(const vec_string* ptr, const size_t idx, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "AT");
+ err->flags |= status.flags;
+ return nullptr;
+ }
+ if (idx >= ptr->size)
+ {
+ __origin_override(err, "AT");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return nullptr;
+ }
+ return &ptr->array[idx];
+}
+
+size_t
+vec_string_begin(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "BEGIN");
+ err->flags |= status.flags;
+ return status.flags;
+ }
+ return 0;
+}
+
+size_t
+vec_string_end(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "END");
+ err->flags |= status.flags;
+ return status.flags;
+ }
+ if (ptr->size == 0)
+ {
+ __origin_override(err, "END");
+ err->flags |= ERR_SIZE_ZERO;
+ return status.flags;
+ }
+ return (size_t)(ptr->size - 1);
+}
+
+String
+vec_string_front(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ String tmp = STR_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "FRONT");
+ err->flags |= status.flags;
+ return tmp;
+ }
+ if (vec_string_at(ptr, 0, err) == nullptr)
+ {
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return tmp;
+ }
+ return *vec_string_at(ptr, 0, err);
+}
+
+String
+vec_string_back(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "BACK");
+ err->flags |= status.flags;
+ return (String)STR_INIT;
+ }
+ if (vec_string_at(ptr, 0, err) == nullptr)
+ {
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return (String)STR_INIT;
+ }
+ return *vec_string_at(ptr, ptr->size - 1, err);
+}
+
+size_t
+vec_string_empty(const vec_string* ptr, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "EMPTY");
+ err->flags |= status.flags;
+ return status.flags;
+ }
+ if (ptr->size == 0)
+ {
+ return ptr->size;
+ }
+ return status.flags;
+}
+
+__attribute__((overloadable)) void
+vec_string_erase(vec_string* ptr, const size_t iter, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "ERASE");
+ err->flags |= status.flags;
+ return;
+ }
+ if (iter >= ptr->size)
+ {
+ return;
+ }
+ memmove(&ptr->array[iter], &ptr->array[iter + 1],
+ (ptr->size - iter - 1) * sizeof(String));
+ ptr->array[ptr->size - 1] = (String)STR_INIT;
+ ptr->size--;
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_erase(vec_string* ptr, const size_t iter_start,
+ const size_t iter_end, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "ERASE");
+ err->flags |= status.flags;
+ return;
+ }
+
+ if (ptr->size < iter_end || iter_end <= iter_start)
+ {
+ __origin_override(err, "ERASE");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+ size_t diff = iter_end - iter_start;
+ memmove(&ptr->array[iter_start], &ptr->array[iter_end],
+ (ptr->size - iter_end) * sizeof(String));
+ memset(&ptr->array[ptr->size - diff], 0, sizeof(String) * diff);
+ ptr->size -= diff;
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_resize(vec_string* ptr, const size_t size, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ __null_check(ptr, &status);
+ if ((status.flags & ERR_VEC_NULL) != 0)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_VEC_NULL;
+ return;
+ }
+
+ if (ptr->size == size)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+
+ else if (size > ptr->max_size)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return;
+ }
+
+ else if ((status.flags & ERR_BUF_NULL) != 0 || ptr->size == 0)
+ {
+ size_t max = ptr->max_size;
+ err_t verr = ERR_T_INIT;
+ vec_string_reserve(ptr, size, &verr);
+ if (verr.flags != 0)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= verr.flags;
+ return;
+ }
+ if (ptr->capacity != size)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_ALLOC_FAIL;
+ return;
+ }
+ for (size_t i = 0; i < size; i++)
+ {
+ ptr->array[i] = (String)STR_INIT;
+ }
+ ptr->max_size = max;
+ ptr->size = size;
+ return;
+ }
+ else if (size > ptr->capacity)
+ {
+ size_t tmpcp = ptr->capacity;
+ size_t tmpmx = ptr->max_size;
+ err_t verr = ERR_T_INIT;
+ while (size > tmpcp)
+ {
+ tmpcp *= 2;
+ }
+ if (tmpcp > ptr->max_size)
+ {
+ tmpcp = size;
+ }
+ vec_string_reserve(ptr, tmpcp, &verr);
+ if (verr.flags != 0)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= verr.flags;
+ return;
+ }
+ if (ptr->capacity != tmpcp)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_ALLOC_FAIL;
+ return;
+ }
+ ptr->max_size = tmpmx;
+ }
+ if (size < ptr->size)
+ {
+ for (size_t i = size; i < ptr->size; i++)
+ {
+ ptr->array[i] = (String)STR_INIT;
+ }
+ }
+ if (ptr->size < size && size <= ptr->capacity)
+ {
+ for (size_t i = ptr->size; i < size; i++)
+ {
+ ptr->array[i] = (String)STR_INIT;
+ }
+ }
+ ptr->size = size;
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_resize(vec_string* ptr, const size_t size, const String val,
+ err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ __null_check(ptr, &status);
+ if ((status.flags & ERR_VEC_NULL) != 0)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_VEC_NULL;
+ return;
+ }
+ if (ptr->size == size)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+
+ else if (size > ptr->max_size)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return;
+ }
+
+ else if ((status.flags & ERR_BUF_NULL) != 0 || ptr->size == 0)
+ {
+ size_t max = ptr->max_size;
+ err_t verr = ERR_T_INIT;
+ vec_string_reserve(ptr, size, &verr);
+ if (verr.flags != 0)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= verr.flags;
+ return;
+ }
+ if (ptr->capacity != size)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= ERR_ALLOC_FAIL;
+ return;
+ }
+ for (size_t i = 0; i < size; i++)
+ {
+ ptr->array[i] = val;
+ }
+ ptr->max_size = max;
+ ptr->size = size;
+ return;
+ }
+ else if (size > ptr->capacity)
+ {
+ size_t tmpcp = ptr->capacity;
+ size_t tmpmx = ptr->max_size;
+ err_t verr = ERR_T_INIT;
+ while (size > tmpcp)
+ {
+ tmpcp *= 2;
+ }
+ if (tmpcp > ptr->max_size)
+ {
+ tmpcp = size;
+ }
+ vec_string_reserve(ptr, tmpcp, &verr);
+ if (verr.flags != 0)
+ {
+ __origin_override(err, "RESIZE");
+ err->flags |= verr.flags;
+ return;
+ }
+ ptr->max_size = tmpmx;
+ }
+ if (size < ptr->size)
+ {
+ for (size_t i = size; i < ptr->size; i++)
+ {
+ ptr->array[i] = val;
+ }
+ }
+ if (ptr->size < size && size <= ptr->capacity)
+ {
+ for (size_t i = ptr->size; i < size; i++)
+ {
+ ptr->array[i] = val;
+ }
+ }
+ ptr->size = size;
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_assign(vec_string* ptr, const vec_string* iterator,
+ const size_t iter_start, const size_t iter_end, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0 ||
+ __null_check(iterator, &status) != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ if (ptr->array == iterator->array)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= ERR_DOUBLE_BUF;
+ return;
+ }
+ if (iterator->size < iter_end || iter_end <= iter_start)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+ vec_string_erase(ptr, vec_string_begin(ptr, &status),
+ vec_string_end(ptr, &status) + 1, &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ vec_string_reserve(ptr, (iter_end - iter_start), &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ for (size_t i = iter_start; i < iter_end; i++)
+ {
+ String* res = vec_string_at(iterator, i, &status);
+ if (res == nullptr)
+ {
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+ vec_string_push_back(ptr, *res, &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ }
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_assign(vec_string* ptr, const size_t amount, const String val,
+ err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ if (__null_check(ptr, &status) != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ if (amount == 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= ERR_SIZE_ZERO;
+ return;
+ }
+ vec_string_erase(ptr, vec_string_begin(ptr, &status),
+ vec_string_end(ptr, &status) + 1, &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ vec_string_reserve(ptr, amount, &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ for (size_t i = 0; i < amount; i++)
+ {
+ vec_string_push_back(ptr, val, &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "ASSIGN");
+ err->flags |= status.flags;
+ return;
+ }
+ }
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_insert(vec_string* ptr, const size_t iter, const String val,
+ err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ __null_check(ptr, &status);
+ if ((status.flags & ERR_VEC_NULL) != 0)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= status.flags;
+ return;
+ }
+ if ((status.flags & ERR_BUF_NULL) != 0)
+ {
+ String* res = malloc(1 * sizeof(String));
+ if (res == nullptr)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= ERR_BUF_NULL;
+ return;
+ }
+ ptr->array = res;
+ ptr->capacity = 1;
+ ptr->array[0] = val;
+ ptr->size = 1;
+ return;
+ }
+ if (ptr->max_size < ptr->size + 1)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= ERR_SIZE_OVERFLOW;
+ return;
+ }
+ if (iter > ptr->size)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+
+ String empty = STR_INIT;
+ vec_string_push_back(ptr, empty, &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= status.flags;
+ return;
+ }
+ for (size_t i = ptr->size - 1; i > iter; i--)
+ {
+ ptr->array[i] = ptr->array[i - 1];
+ }
+ ptr->array[iter] = val;
+
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_insert(vec_string* ptr, const size_t iter, const size_t amount,
+ const String val, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ __null_check(ptr, &status);
+ if ((status.flags & (ERR_VEC_NULL | ERR_BUF_NULL)) != 0)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= status.flags;
+ return;
+ }
+ if (iter > ptr->size)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+ if (amount == 0)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= ERR_SIZE_ZERO;
+ return;
+ }
+ for (size_t i = iter; i < iter + amount; i++)
+ {
+ vec_string_insert(ptr, i, val, &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= status.flags;
+ return;
+ }
+ }
+ return;
+}
+
+__attribute__((overloadable)) void
+vec_string_insert(vec_string* ptr, const vec_string* iterator,
+ const size_t iter, const size_t iter_start,
+ const size_t iter_end, err_t* err)
+{
+ err_t status = ERR_T_INIT;
+ __null_check(ptr, &status);
+ __null_check(iterator, &status);
+ if ((status.flags & (ERR_VEC_NULL | ERR_BUF_NULL)) != 0)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= status.flags;
+ return;
+ }
+ if (iter_end <= iter_start || iter_end > iterator->size ||
+ iter > ptr->size)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= ERR_OUT_OF_BOUNDS;
+ return;
+ }
+ if (ptr->array == iterator->array)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= ERR_DOUBLE_BUF;
+ return;
+ }
+ for (size_t i = iter_start; i < iter_end; i++)
+ {
+ vec_string_insert(ptr, iter + (i - iter_start),
+ iterator->array[i], &status);
+ if (status.flags != 0)
+ {
+ __origin_override(err, "INSERT");
+ err->flags |= status.flags;
+ return;
+ }
+ }
+ return;
+}
diff --git a/src/utils.c b/src/utils.c
index 71d0c55..7765cf9 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -36,7 +36,7 @@ vec_print_errs(const err_t err)
}
void
-print_bits(unsigned int num)
+vec_print_bits(unsigned int num)
{
unsigned int total_bits = sizeof(num) * 8;