This is pretty straightforward. More could be done:

1. small array optimization
2. support for ranges as constructor args
3. present a range interface
4. support for malloc/free instead of GC
5. bounds checking
6. the array[] and the count could be allocated together
7. array[] could be just a pointer

but the basic idea is there, I didn't want to hide it behind all the other flesh a professional type would have.

Note the return in opIndex(). This is DIP25 at work!

Compile:
    dmd rcarray -unittest -main -dip25

===========================================

struct RCArray(E) {

    this(E[] a)
    {
        array = a.dup;
        start = 0;
        end = a.length;
        count = new int;
        *count = 1;
    }

    ~this()
    {
        if (count && --*count == 0)
            delete array;
    }

    this(this)
    {
        if (count)
            ++*count;
    }

    size_t length()
    {
        return end - start;
    }

    ref E opIndex(size_t i) return // here's the magic
    {
        return array[start + i];
    }

    RCArray opSlice(size_t lwr, size_t upr)
    {
        RCArray result = this;
        result.start = start + lwr;
        result.end = start + upr;
        return result;
    }

  private:
    E[] array;
    size_t start, end;
    int* count;
}

unittest
{
    static int[3] s = [7, 6, 4];
    auto r = RCArray!int(s);
    assert(r.length == 3);
    assert(r[0] == 7);
    assert(r[1] == 6);
    assert(r[2] == 4);
    assert(*r.count == 1);

    {
        auto r2 = r;
        assert(r2[0] == 7);
        assert(r2[1] == 6);
        assert(r2[2] == 4);
        assert(*r.count == 2);

        r[1] = 3;
        assert(r2[0] == 7);
        assert(r2[1] == 3);
        assert(r2[2] == 4);
    }
    assert(*r.count == 1);

    auto r3 = r[1 .. 3];
    r[2] = 9;
    assert(r3[0] == 3);
    assert(r3[1] == 9);

  /+
    ref int test(ref RCArray!int rr)
    {
        return rr[1]; // this gives error
    }
   +/
}

Reply via email to