1 module simplefixedsizearray; 2 3 struct SFA(T,size_t Size = 32) { 4 static assert(Size > 0); 5 import std.traits : CopyTypeQualifiers, hasElaborateDestructor, hasMember; 6 7 static if(Size <= ubyte.max) { 8 ubyte length_; 9 } else static if(Size <= ushort.max) { 10 ushort length_; 11 } else { 12 size_t length_; 13 } 14 15 ubyte[T.sizeof * Size] store; 16 17 ~this() { 18 static if(hasElaborateDestructor!T) { 19 this.removeAll(); 20 } 21 } 22 23 struct SFARange(S,U) { 24 S* ptr; 25 size_t low; 26 size_t high; 27 28 @property bool empty() const pure @safe nothrow @nogc { 29 return this.low >= this.high; 30 } 31 32 pragma(inline, true) 33 @property size_t length() pure @safe nothrow @nogc { 34 return cast(size_t)(this.high - this.low); 35 } 36 37 @property ref U front() { 38 return (*this.ptr)[this.low]; 39 } 40 41 @property ref U back() { 42 return (*this.ptr)[this.high - 1]; 43 } 44 45 ref T opIndex(const size_t idx) { 46 return (*this.ptr)[this.low + idx]; 47 } 48 49 void popFront() pure @safe nothrow @nogc { 50 ++this.low; 51 } 52 53 void popBack() pure @safe nothrow @nogc { 54 --this.high; 55 } 56 57 @property typeof(this) save() pure @safe nothrow @nogc { 58 return this; 59 } 60 } 61 62 SFARange!(typeof(this), CopyTypeQualifiers!(S,T)) opSlice(this S)(size_t low, size_t high) { 63 assert(low <= high); 64 assert(low <= this.length_); 65 return typeof(return)(&this, low, high); 66 } 67 68 SFARange!(typeof(this), CopyTypeQualifiers!(S,T)) opSlice(this S)() { 69 return typeof(return)(&this, 0U, this.length); 70 } 71 72 @property size_t length() const @safe pure nothrow @nogc { 73 return cast(size_t)this.length_; 74 } 75 76 @property bool empty() const @safe @nogc nothrow { 77 return this.length_ == 0U; 78 } 79 80 @property bool hasCapacity() const @safe @nogc nothrow { 81 return (this.length * T.sizeof) < this.store.length; 82 } 83 84 void insertBack(T t) { 85 assert(this.length + 1 <= Size); 86 *(cast(T*)(&this.store[cast(size_t)(this.length * T.sizeof)])) = t; 87 ++this.length_; 88 } 89 90 ref CopyTypeQualifiers!(S,T) opIndex(this S)(size_t idx) { 91 idx *= T.sizeof; 92 assert(idx < this.store.length); 93 return *(cast(T*)&(this.store[idx])); 94 } 95 96 @property ref CopyTypeQualifiers!(S,T) front(this S)() { 97 assert(!this.empty); 98 return *(cast(T*)(&this.store[0U])); 99 } 100 101 @property ref CopyTypeQualifiers!(S,T) back(this S)() { 102 import std.stdio; 103 assert(!this.empty); 104 return *(cast(T*)(&this.store[(this.length * T.sizeof) - T.sizeof])); 105 } 106 107 void removeAll() { 108 while(!this.empty) { 109 this.removeBack(); 110 } 111 } 112 113 void removeBack() { 114 assert(!this.empty); 115 116 static if(hasElaborateDestructor!T) { 117 static if(hasMember!(T, "__dtor")) { 118 this.back().__dtor(); 119 } else static if(hasMember!(T, "__xdtor")) { 120 this.back().__xdtor(); 121 } else { 122 static assert(false); 123 } 124 } 125 126 --this.length_; 127 } 128 129 void remove(size_t idx) { 130 assert(idx < this.length); 131 static if(hasElaborateDestructor!T) { 132 static if(hasMember!(T, "__dtor")) { 133 this[idx].__dtor(); 134 } else static if(hasMember!(T, "__xdtor")) { 135 this[idx].__xdtor(); 136 } else { 137 static assert(false); 138 } 139 } 140 141 for(size_t i = idx * T.sizeof; i < ((this.length - 1U) * T.sizeof); ++i) { 142 this.store[i] = this.store[i + T.sizeof]; 143 } 144 145 --this.length_; 146 } 147 } 148 149 unittest { 150 SFA!(int) a; 151 } 152 153 unittest { 154 SFA!(int) a; 155 assert(a.hasCapacity); 156 a.insertBack(10); 157 assert(a[0] == 10); 158 assert(a.front == 10); 159 assert(a.back == 10); 160 a.removeBack(); 161 assert(a.empty); 162 } 163 164 unittest { 165 struct Foo { 166 size_t value; 167 alias value this; 168 169 ~this() { 170 } 171 } 172 173 void test(size_t Size, T)() { 174 static import std.algorithm; 175 import std.stdio; 176 SFA!(T, Size) a; 177 assert(a.empty); 178 foreach(it; 0 .. Size) { 179 assert(a.hasCapacity); 180 a.insertBack(T(it)); 181 assert(a.length == it + 1); 182 assert(a.front == 0); 183 assert(a.back == it); 184 185 foreach(jt; 0 .. it + 1) { 186 assert(a[jt] == jt); 187 } 188 189 auto r = a[0 .. a.length]; 190 auto r2 = r.save(); 191 192 //writefln!"%d %d"(r.low, r.high); 193 assert(!r.empty); 194 assert(r.front == 0); 195 assert(r.back == it); 196 197 size_t idx = 0; 198 foreach(jt; r) { 199 assert(jt == idx); 200 ++idx; 201 } 202 203 idx = it; 204 foreach_reverse(jt; r2) { 205 assert(jt == idx); 206 --idx; 207 } 208 } 209 assert(!a.hasCapacity); 210 } 211 212 static foreach(tSize; [1,2,3,4,5,10,11,32,63,64,256]) { 213 test!(tSize, size_t)(); 214 test!(tSize, Foo)(); 215 } 216 } 217 218 unittest { 219 import std.stdio; 220 SFA!(int) a; 221 foreach(it; [0,1,2,3,4,5,6,7,8,9]) { 222 a.insertBack(it); 223 } 224 225 a.remove(5); 226 227 foreach(idx, it; [0,1,2,3,4,6,7,8,9]) { 228 assert(a[idx] == it); 229 } 230 } 231 232 unittest { 233 SFA!int a; 234 a.insertBack(1337); 235 a.remove(0); 236 assert(a.empty); 237 } 238 239 unittest { 240 import std.stdio; 241 SFA!(int) a; 242 foreach(it; 0 .. 10) { 243 a.insertBack(it); 244 assert(a.length == it + 1); 245 } 246 247 auto r = a[]; 248 foreach(it; 0 .. 10) { // Slice.opIndex 249 assert(r[it] == it); 250 } 251 252 for(size_t i = 0; !r.empty; r.popFront(), ++i) { 253 assert(r.length == 10 - i); 254 auto f = r.front; 255 foreach(it; i .. 10) { 256 //writefln!"%d %d"(r[it - i], it); 257 assert(r[it - i] == it); 258 } 259 } 260 }