Skip to content

VecInitStack

Description

Stack-backed Vec scope. The macro declares name as a Vec(T) whose backing storage is a fixed-capacity stack array of ne elements, then opens a scope where the body sees name as an initialised, empty vector. name’s lexical scope is exactly the body: outside the macro the identifier is no longer bound.

No allocator – the backing storage is the stack. The body is responsible for keeping content bounded by ne. Any operation that would grow name past ne ends up calling VecReserve, which sees the NULL allocator and aborts via LOG_FATAL("vector not growable, no allocator assigned, probably stack inited"). Deep-copy callbacks are out of scope for stack-backed Vecs: if you need inner-resource deep copies, use a heap-backed Vec where the allocator is unambiguous.

The macro uses the for-chain scope idiom – the body is regular code below the macro, not a brace-delimited argument:

VecInitStack(int, v, 16) { VecPushBackR(&v, 42); … }

T is the element type; the macro mints a fresh Vec(T) struct for name. This matches how StrInitStack(name, ne) mints a fresh Str – callers do not pre-declare the variable.

Success

Body runs once; name is valid for the body’s scope. On normal fall-through, backing array and the Vec handle are both zeroed by the macro’s exit updates.

Failure

The macro itself cannot fail. Operations inside the body that try to grow name past ne abort.

updates. break exits the innermost for cleanly: the backing array is still zeroed by the outer for’s update, but the inner update that zeroes the name handle is skipped – harmless because name’s scope is the body anyway and the identifier is no longer reachable after the macro. continue inside the body does NOT restart – it jumps to the inner for’s update clause, which zeroes name and exits the scope; treat it as a silent early-exit, not a loop control. ne is evaluated twice in the macro body (once in the array dimension sizeof(T) * ((ne) + 1), once in the Vec(T) capacity assignment); sizeof(UNPL(_s).d) reads the array’s type, not ne. Pass a side-effect-free expression (literal or simple variable) regardless.

Usage example (Cross-references)

Usage examples (Cross-references)
        }
        bool ok = false;
        VecInitStack(u8, buf, 28) {
            if (!stream_read(self, 1, 0, VecBegin(&buf), VecCapacity(&buf)))
                break;
            mfc_tsm_idx = 0, optdbg_size = 0, ec_size = 0, padding = 0;
        u16 global_idx = 0, build_num = 0, public_idx = 0, pdb_dll_ver = 0, pdb_dll_rbld = 0, flags = 0, machine = 0;
        VecInitStack(u8, hdr, DBI_HEADER_SIZE) {
            if (!stream_read(self, DBI_STREAM_INDEX, 0, VecBegin(&hdr), VecCapacity(&hdr)))
                break;
            return r;
    
        VecInitStack(u8, sh, 2) {
            if (!stream_read(self, DBI_STREAM_INDEX, sec_hdr_off, VecBegin(&sh), 2))
                break;
    // Test vector stack initialization
    bool test_vec_init_stack(void) {
        WriteFmt("Testing VecInitStack\n");
    
        bool result = true;
        // VecInitStack declares and scopes `vec` itself (for-chain idiom),
        // matching StrInitStack.
        VecInitStack(int, vec, 10) {
            // Stack-init: NULL allocator distinguishes from heap-init.
            if (VecLen(&vec) != 0 || VecCapacity(&vec) != 10 || VecBegin(&vec) == NULL ||
    
        // Test with struct type
        VecInitStack(TestItem, test_vec, 5) {
            if (VecLen(&test_vec) != 0 || VecCapacity(&test_vec) != 5 || VecBegin(&test_vec) == NULL ||
                VecAllocator(&test_vec) != NULL) {
            f64 b;
        } AlignedItem;
        VecInitStack(AlignedItem, av, 4) {
            if ((size)(void *)VecBegin(&av) % _Alignof(AlignedItem) != 0) {
                result = false;
        // `break` exit path: the body breaks early; the backing buffer's
        // outer-for update still runs.
        VecInitStack(int, breakable, 8) {
            VecPushBackR(&breakable, 1);
            if (VecLen(&breakable) != 1) {
Last updated on