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 }