February 23, 2015 A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
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 } +/ } |
February 23, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On 2/23/15 2:15 PM, Walter Bright wrote:
> This is pretty straightforward.
[snip]
The code builds if you slap a "@safe:" at the top. There is one bug in the compiler: "delete" must not be allowed in @safe code. The destructor must be @trusted.
Understanding that this code (sans delete) is @safe (and the contribution of DIP25 to that) is of paramount importance.
Making it possible to define @safe structs that are still able to return reference to their internals is crucial. It paves the way for truly safe reference counted classes.
Andrei
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright:
> 5. bounds checking
When you go past bounds of a built-in array you get an error located in the user code, while if you put a pre-condition in your Array struct to detect the same errors, you get a run-time error message located in that pre-condition instead. I'd like some way to solve this small problem of giving more correctly located error messages. In Contract programming lingo it's a problem of "blame management" (I'd also like a way to detect some compile-time out-of-bound errors for user-defined collections, but you said this is not worth the effort).
Bye,
bearophile
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | I thought that delete is deprecated, yet here Walter himself promotes a solution that uses it.
Can we *PLEASE* finally deprecate things that are supposed to be deprecated and remove things that are supposed to be removed?
On 2015-02-23 22:15:46 +0000, Walter Bright said:
> 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
> }
> +/
> }
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On 2/23/2015 4:13 PM, bearophile wrote:
>> 5. bounds checking
>
> When you go past bounds of a built-in array you get an error located in the user
> code, while if you put a pre-condition in your Array struct to detect the same
> errors, you get a run-time error message located in that pre-condition instead.
> I'd like some way to solve this small problem of giving more correctly located
> error messages. In Contract programming lingo it's a problem of "blame
> management" (I'd also like a way to detect some compile-time out-of-bound errors
> for user-defined collections, but you said this is not worth the effort).
This is off-topic. The point of the array class as presented is to show how a memory safe reference counted container can be built.
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Klyga | On 2/23/2015 5:01 PM, Max Klyga wrote:
> I thought that delete is deprecated, yet here Walter himself promotes a solution
> that uses it.
> Can we *PLEASE* finally deprecate things that are supposed to be deprecated and
> remove things that are supposed to be removed?
That isn't the point. I could have well have used malloc/free, but I wanted the code example to be about how to make a memory safe ref counted container, not about the details of memory allocation. It demonstrates how 'return ref' is to be used.
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Monday, 23 February 2015 at 22:15:54 UTC, Walter Bright wrote:
> ref E opIndex(size_t i) return // here's the magic
exactly what is this doing? I don't see this explained in DIP25 at all.
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to weaselcat | On 2/23/2015 5:41 PM, weaselcat wrote:
> On Monday, 23 February 2015 at 22:15:54 UTC, Walter Bright wrote:
>> ref E opIndex(size_t i) return // here's the magic
>
> exactly what is this doing? I don't see this explained in DIP25 at all.
The 'this' is passed by reference. So the 'return' is really 'return ref this', the rest is explained by DIP25.
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Tuesday, 24 February 2015 at 02:06:07 UTC, Walter Bright wrote:
> On 2/23/2015 5:41 PM, weaselcat wrote:
>> On Monday, 23 February 2015 at 22:15:54 UTC, Walter Bright wrote:
>>> ref E opIndex(size_t i) return // here's the magic
>>
>> exactly what is this doing? I don't see this explained in DIP25 at all.
>
> The 'this' is passed by reference. So the 'return' is really 'return ref this', the rest is explained by DIP25.
Oh, I see. That makes a lot more sense.
|
February 24, 2015 Re: A Refcounted Array Type | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Monday, February 23, 2015 15:28:21 Andrei Alexandrescu via Digitalmars-d wrote:
> On 2/23/15 2:15 PM, Walter Bright wrote:
> > This is pretty straightforward.
> [snip]
>
> The code builds if you slap a "@safe:" at the top. There is one bug in the compiler: "delete" must not be allowed in @safe code. The destructor must be @trusted.
And delete is supposed to have been deprecated ages ago, but yeah, it _definitely_ shouldn't be considered @safe.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation