1 module dvector; 2 3 version(LDC){ 4 pragma(LDC_no_moduleinfo); 5 } 6 7 import core.stdc.stdlib; 8 import core.stdc.string; 9 10 private enum CAPACITY = 4; 11 12 struct Dvector(T) { 13 private T* chunks; 14 size_t total; 15 size_t capacity; 16 17 @property T front() @nogc nothrow { 18 return chunks[0]; 19 } 20 21 @property T back() @nogc nothrow { 22 return chunks[length-1]; 23 } 24 25 size_t length() @nogc nothrow { 26 return total; 27 } 28 29 @property bool empty() const @nogc nothrow { 30 return total == 0; 31 } 32 33 void popFront() @nogc nothrow { 34 remove(0); 35 } 36 37 void popBack() @nogc nothrow { 38 remove(length-1); 39 } 40 41 /** !!! WARNING !!! 42 Use it carefully with the standard library. 43 Be sure that the standard library functions don't implicitly copy it. 44 But, it is Ok if the standard library functions return a handle of copied range 45 so that you can free it manually. Otherwise, you leak memory. 46 */ 47 Dvector!T save() const @nogc nothrow { 48 T* cc_chunks = cast(T*)malloc(T.sizeof * this.capacity); 49 memcpy(cc_chunks, chunks, capacity * T.sizeof); 50 return Dvector!T(cc_chunks, this.total, this.capacity); 51 } 52 53 this(T* chunks, size_t total, size_t capacity) @nogc nothrow { 54 this.chunks = chunks; 55 this.total = total; 56 this.capacity = capacity; 57 } 58 59 void pushBack(T elem) @nogc nothrow { 60 allocIfneeded(); 61 if (capacity == total) 62 resize(capacity * 2); 63 chunks[total++] = elem; 64 } 65 66 alias pBack = pushBack; 67 68 ref T opIndex(size_t i) @nogc nothrow { 69 return chunks[i]; 70 } 71 72 void opIndexAssign(T elem, size_t i) @nogc nothrow { 73 chunks[i] = elem; 74 } 75 76 void remove(size_t index) @nogc nothrow { 77 for (size_t i = index; i < total - 1; i++) { 78 chunks[i] = chunks[i + 1]; 79 } 80 81 total--; 82 83 if (total > 0 && total == capacity / 4){ 84 resize(capacity / 2); 85 } 86 } 87 88 void allocIfneeded() @nogc nothrow { 89 if(chunks is null){ 90 capacity = CAPACITY; 91 T* _chunks = cast(T*)malloc(T.sizeof * CAPACITY); 92 this.chunks = _chunks; 93 } 94 } 95 96 void resize(size_t capacity) @nogc nothrow { 97 version(Debug){ 98 import core.stdc.stdio; 99 printf("resize: %d to %d\n", this.capacity, capacity); 100 } 101 102 T* chunks = cast(T*)realloc(this.chunks, T.sizeof * capacity); 103 if (chunks) { 104 this.chunks = chunks; 105 this.capacity = capacity; 106 } 107 } 108 109 void free() @nogc nothrow { 110 total = 0; 111 capacity = CAPACITY; 112 core.stdc.stdlib.free(chunks); 113 chunks = null; 114 } 115 116 int opApply(int delegate(ref T) @nogc nothrow dg) @nogc nothrow{ 117 int result = 0; 118 119 for (size_t k = 0; k < total; ++k) { 120 result = dg(chunks[k]); 121 122 if (result) { 123 break; 124 } 125 } 126 return result; 127 } 128 129 int opApply(int delegate(size_t i, ref T) @nogc nothrow dg) @nogc nothrow{ 130 int result = 0; 131 132 for (size_t k = 0; k < total; ++k) { 133 result = dg(k, chunks[k]); 134 135 if (result) { 136 break; 137 } 138 } 139 return result; 140 } 141 142 // overloads for gc usages: 143 int opApply(int delegate(ref T) dg){ 144 int result = 0; 145 146 for (size_t k = 0; k < total; ++k) { 147 result = dg(chunks[k]); 148 149 if (result) { 150 break; 151 } 152 } 153 return result; 154 } 155 156 int opApply(int delegate(size_t i, ref T) dg){ 157 int result = 0; 158 159 for (size_t k = 0; k < total; ++k) { 160 result = dg(k, chunks[k]); 161 162 if (result) { 163 break; 164 } 165 } 166 return result; 167 } 168 169 Dvector!T opBinary(string op)(ref Dvector!T rhs) @nogc nothrow{ 170 static if (op == "~"){ 171 allocIfneeded(); 172 foreach(elem; rhs) 173 pushBack(elem); 174 return this; 175 } 176 else static assert(0, "Operator "~op~" not implemented"); 177 } 178 179 Dvector!T opBinary(string op)(T rhs) @nogc nothrow { 180 static if (op == "~"){ 181 allocIfneeded(); 182 pushBack(rhs); 183 return this; 184 } 185 else static assert(0, "Operator "~op~" not implemented"); 186 } 187 188 @nogc nothrow Dvector!T opOpAssign(string op)(ref Dvector!T rhs) if (op == "~"){ 189 allocIfneeded(); 190 foreach(elem; rhs) 191 pushBack(elem); 192 return this; 193 } 194 195 @nogc nothrow Dvector!T opOpAssign(string op)(ref T rhs) if (op == "~"){ 196 allocIfneeded(); 197 pushBack(rhs); 198 return this; 199 } 200 201 void pushFront(T elem) @nogc nothrow{ 202 allocIfneeded(); 203 pushBack(T.init); 204 205 for(size_t i = length-1; i > 0; i--){ 206 chunks[i] = chunks[i - 1]; 207 } 208 chunks[0] = elem; 209 } 210 211 void insert(T elem, size_t position) @nogc nothrow{ 212 allocIfneeded(); 213 pushBack(T.init); 214 215 for (size_t k = length-1; k > position; k--) 216 chunks[k] = chunks[k - 1]; 217 chunks[position] = elem; 218 } 219 220 T[] slice() @nogc nothrow{ 221 return chunks[0..length]; 222 } 223 } 224 225 unittest { 226 import core.stdc.stdio; 227 struct Person { string name; uint score;} 228 229 Dvector!(Person) prs1; 230 231 auto p1 = Person("ferhat", 5); 232 auto p2 = Person("Mike", 3); 233 auto p3 = Person("Rajneesh", 1); 234 auto p4 = Person("Ce", 2); 235 236 prs1 ~= p1; 237 prs1 ~= p2; 238 prs1 ~= p3; 239 prs1 ~= p4; 240 241 Dvector!(Person) prs2; 242 auto s1 = Person("Ezgi", 15); 243 auto s2 = Person("Emine", 36); 244 245 prs2 ~= s1; 246 prs2 ~= s2; 247 248 auto comb = prs1 ~ prs2; 249 250 comb.remove(2); 251 252 assert(comb[2].name == "Ce"); 253 254 auto cn = Person("Chuck", 100); 255 comb.pushFront(cn); 256 257 assert(comb[0].name == "Chuck"); 258 259 auto srv = Person("SRV", 100); 260 comb.insert(srv, 3); 261 262 assert(comb[3].name == "SRV"); 263 264 foreach(i, p; comb){ 265 printf("%d: %s \n", i, p.name.ptr); 266 } 267 268 comb.free; 269 prs2.free; 270 }