1 /// Storage
2 module grain.storage;
3 
4 
5 /// Basic storage
6 struct Storage(Allocator_)
7 {
8     alias Allocator = Allocator_;
9     
10     static if(is(typeof(Allocator.deviceof))) {
11         enum deviceof = Allocator.deviceof;
12     } else {
13         enum deviceof = "cpu";
14     }
15 
16     static if(is(typeof(Allocator.pinned))) {
17         enum pinned = Allocator.pinned;
18     } else {
19         enum pinned = false;
20     }
21     
22     void[] payload;
23     Allocator allocator;
24     alias payload this;
25 
26     @disable this(this);
27     @disable new(size_t);
28     
29     this(size_t bytes, Allocator a = Allocator.instance)
30     {
31         this.allocator = a;
32         this.payload = a.allocate(bytes);
33     }
34 
35     ~this()
36     {
37         this.allocator.deallocate(this.payload);
38     }
39 }
40 
41 
42 /// Reference count storage
43 struct RCStorage(Allocator_)
44 {
45     import mir.rc.ptr : RCPtr, createRC;
46 
47     alias Allocator = Allocator_;
48     alias Base = Storage!Allocator;
49 
50     RCPtr!Base base;
51     alias base this;
52     
53     this(size_t bytes, Allocator a = Allocator.instance)
54     {
55         this.base = createRC!Base(bytes, a);
56     }
57 
58     RCIter!(It, typeof(this)) iterator(It)()
59     {
60         return typeof(return)(cast(It) this.base.ptr, this);
61     }
62 
63     RCIter!(It, const typeof(this)) iterator(It)() const
64     {
65         return typeof(return)(cast(It) this.base.ptr, this);
66     }
67 }
68 
69 /// Iterator for RCStorage that shares ownership by itself
70 struct RCIter(It, Rc)
71 {
72     import mir.ndslice.traits : isIterator;
73     static assert(isIterator!It);
74     
75     It _iterator;
76     Rc _rc;  // hold ownership here
77 
78     alias T = typeof(*It.init);
79 
80     private inout payload()
81     {
82         return cast(It) _rc.payload;
83     }
84 
85     ///
86     inout(T)* lightScope()() scope return inout @property @trusted
87     {
88         debug
89         {
90             assert(payload <= _iterator);
91             assert(_iterator is null || _iterator <= payload + _rc.length / T.sizeof);
92         }
93         return _iterator;
94     }
95     
96     ///   
97     ref inout(T) opUnary(string op : "*")() inout scope return
98     {
99         debug
100         {
101             assert(_iterator);
102             assert(payload);
103             assert(payload <= _iterator);
104             assert(_iterator <= payload + _rc.length / T.sizeof);
105         }
106         return *_iterator;
107     }
108 
109     ///   
110     ref inout(T) opIndex(ptrdiff_t index) inout scope return @trusted
111     {
112         debug
113         {
114             assert(_iterator);
115             assert(payload);
116             assert(payload <= _iterator + index);
117             assert(_iterator + index <= payload + _rc.length / T.sizeof);
118         }
119         return _iterator[index];
120     }
121 
122     ///   
123     void opUnary(string op)() scope
124         if (op == "--" || op == "++")
125     { mixin(op ~ "_iterator;"); }
126 
127     ///   
128     void opOpAssign(string op)(ptrdiff_t index) scope
129         if (op == "-" || op == "+")
130     { mixin("_iterator " ~ op ~ "= index;"); }
131 
132     ///
133     RCIter!(It, Rc) opBinary(string op)(ptrdiff_t index)
134         if (op == "+" || op == "-")
135     { return typeof(return)(_iterator + index, _rc); }
136 
137     ///   
138     RCIter!(const It, RC) opBinary(string op)(ptrdiff_t index) const
139         if (op == "+" || op == "-")
140     { return typeof(return)(_iterator + index, _rc); }
141 
142     ///   
143     RCIter!(immutable It, RC) opBinary(string op)(ptrdiff_t index) immutable
144         if (op == "+" || op == "-")
145     { return typeof(return)(_iterator + index, _rc); }
146 
147     ///   
148     ptrdiff_t opBinary(string op : "-")(scope ref const typeof(this) right) scope const
149     { return this._iterator - right._iterator; }
150 
151     ///   
152     bool opEquals()(scope ref const typeof(this) right) scope const
153     { return this._iterator == right._iterator; }
154 
155     ///   
156     ptrdiff_t opCmp()(scope ref const typeof(this) right) scope const
157     { return this._iterator - right._iterator; }
158 }
159 
160 import grain.allocator : CPUMallocator;
161 alias DefaultCPUStorage = RCStorage!CPUMallocator;
162 
163 /// Refrence counting string
164 struct RCString
165 {
166     import mir.rc.array : RCArray, rcarray;
167     RCArray!(immutable char) payload;
168     alias toString this;
169     
170     this(scope const(char)[] s) @nogc @safe pure nothrow
171     {
172         this = s;
173     }
174 
175     void opAssign(scope const(char)[] rhs) @nogc @safe pure nothrow
176     {
177         this.payload = rcarray!(immutable char)(rhs);
178     }
179     
180     string toString() return scope @nogc @safe pure nothrow const
181     {
182         return this.payload[];
183     }
184 
185 }
186 
187 ///
188 @safe @nogc pure nothrow
189 unittest
190 {
191     void f(string) {}
192     RCString r;
193     {
194         auto s1 = "hello, world";
195 
196         // assign (copy)
197         r = s1;
198         assert(&r[0] != &s1[0]);
199 
200         // able to copy mutable string
201         char[100] s;
202         s[0 .. s1.length] = s1;
203         r = s;
204         r = RCString(s[0 .. s1.length]);
205     }
206     assert(r == "hello, world");
207 }