On 10/1/23 10:34 AM, Steven Schveighoffer wrote:


The complexity is from the way d does operator overloading and indexing.

It should be pretty straightforward. I’ll see if I can post a simple wrapper.

I didn't tackle any attribute or memory safety issues, or many operator overloads, but this is going to be reasonably close. It should make a copy of the data when copied.

Note this still uses the GC for storage, and when expanding, uses the GC to fetch the capacity (this could be done in one call, but meh).

Some niceties of builtin arrays may not work, but this is somewhat of the cost you pay for trying to make a custom type.

```d
struct VTArray(T)
{
    private T[] _storage;
    private size_t _length;

    const size_t length() => _length;

    void length(size_t newLen) {
        if(newLen <= _storage.length)
            _length = newLen;
        else
        {
            _storage.length = newLen;
            _storage.length = _storage.capacity;
        }
    }

    inout this(ref inout(VTArray) other)
    {
        this(other[]);
    }

    inout this(inout(T)[] buf)
    {
        auto x = buf.dup;
        x.length = x.capacity;
        _length = buf.length;
        _storage = cast(inout)x;
    }

    ref inout(T) opIndex(size_t idx) inout {
        assert(idx < length);
        return _storage[idx];
    }

    void opOpAssign(string s : "~", V)(auto ref V other) {
        static if(is(V == T[]))
        {
            immutable avail = _storage.length - length;
            if(avail < other.length)
            {
                _storage[length .. $] = other[0 .. avail];
                _storage ~= other[avail .. $];
                _storage.length = _storage.capacity; // expand to capacity;
            }
            else
            {
                _storage[length .. length + other.length] = other;
            }
            _length += other.length;
        }
        else static if(is(V == T))
        {
            if(length == _storage.length)
            {
                _storage.length += 1;
                _storage.length = _storage.capacity;
            }
            _storage[_length++] = other;
        }
        else static if(is(V == VTArray))
        {
            this ~= other[];
        }
    }

    void opAssign(T[] arr)
    {
        _storage = arr.dup;
        _storage.length = _storage.capacity;
        _length = arr.length;
    }

    void opAssign(VTArray vtarr)
    {
        this = vtarr._storage[0 .. vtarr.length];
    }

    inout(T)[] opIndex() inout => _storage[0 .. _length];

    void toString(Out)(auto ref Out output)
    {
        import std.format;
        formattedWrite(output, "%s", this[]);
    }
}

void main()
{
    auto arr = VTArray!int.init;
    arr ~= 1;
    arr ~= [2,3,4,5];
    import std.stdio;
    writeln(arr);
    auto arr2 = arr;
    arr2[0] = 5;
    writeln(arr);
    writeln(arr2);
    arr2 ~= arr;
    writeln(arr2);
}
```

This should give you a reasonable head-start.

-Steve

Reply via email to