Have you checked what push_stuff actually returns with those inputs?
Right, we get [0xFF, 0xFF, 'A'] and [0xFF, 0xFF].

I think the following is a pretty easy workaround though:

alias usize = size_t;

struct Push_Buf(T, usize stack_size) {
    T[stack_size] stack_buf;
    T[] heap_buf;
    usize p = 0;

    void opOpAssign(string op)(T e) if (op == "~") {
        if (p < stack_size) {
            stack_buf[p] = e;
            p += 1;
        }
        else {
            if (p == stack_size) {
                heap_buf = stack_buf.dup();
                p += 1;
            }
            heap_buf ~= e;
        }
    }

    void opOpAssign(string op)(immutable(T)[] es) if (op == "~") {
        if (p + es.length <= stack_size) {
            import core.stdc.string : memcpy;
            memcpy(&stack_buf[p], es.ptr, es.length);
            p += es.length;
        }
        else {
            if (p < stack_size) {
                heap_buf = stack_buf[0 .. p].dup();
                p += es.length;
            }
            heap_buf ~= es;
        }
    }

    U opCast(U: T[])() { return as_slice(); }
U opCast(U: immutable(T)[])() { return cast(immutable(T)[]) as_slice(); }

    @property T[] as_slice() {
        if (p <= stack_size) { return stack_buf[0 .. p]; }
        else return heap_buf;
    }

    alias as_slice this;
}

string push_stuff(usize buf_size)(ref Push_Buf!(char, buf_size) buf, int x) {
    if (x == 1) {
        buf ~= 'A';
        buf ~= 'B';
        buf ~= 'C';
    }
    else {
        buf ~= 'A';
        buf ~= 'B';
    }
    return cast(string) buf;
}

void foo() {
    {
        Push_Buf!(char, 2) buf;
        string result = push_stuff(buf, 1);
        assert(buf.heap_buf.ptr == result.ptr);
    }
    {
        Push_Buf!(char, 2) buf;
        string result = push_stuff(buf, 0);
        assert(buf.stack_buf.ptr == result.ptr);
    }
}

Reply via email to