1 module yu.container.vector; 2 3 import core.memory; 4 import std.exception; 5 import std.experimental.allocator; 6 import std.experimental.allocator.mallocator; 7 import std.experimental.allocator.gc_allocator; 8 import yu.traits; 9 import core.stdc.string : memcpy, memset; 10 import yu.container.common; 11 import yu.array; 12 13 /** 14 * copy 有三种类型: 15 1. COW: 对于值类型, 非指针, 对于结构体并且没有自定义 赋值函数 16 2. 深Copy: 对于有自定义 赋值函数的结构体 17 2. 不允许copy: 对于引用类型 和 指针 18 */ 19 20 @trusted struct Vector(T, Allocator = Mallocator, bool addInGC = true) if(is(T == Unqual!T)) 21 { 22 enum addToGC = addInGC && hasIndirections!T && !is(Unqual!Allocator == GCAllocator); 23 enum needDestroy = (is(T == struct) && hasElaborateDestructor!T); 24 enum isNotCopy = isPointer!T || isRefType!T; 25 alias Data = ArrayCOWData!(T, Allocator,addToGC); 26 static if (hasIndirections!T) 27 alias InsertT = T; 28 else 29 alias InsertT = const T; 30 31 static if (StaticAlloc!Allocator) 32 { 33 this(size_t size) 34 { 35 reserve(size); 36 } 37 38 this(S)(S[] data) if(is(S : InsertT)) 39 { 40 assign(data); 41 } 42 } 43 else 44 { 45 @disable this(); 46 this(size_t size,Allocator alloc) 47 { 48 _alloc = alloc; 49 reserve(size); 50 } 51 52 this(S)(S[] data,Allocator alloc) if(is(S : InsertT)) 53 { 54 _alloc = alloc; 55 assign(data); 56 } 57 58 this(Allocator alloc) 59 { 60 _alloc = alloc; 61 } 62 } 63 mixin AllocDefine!Allocator; 64 static if(isNotCopy){ 65 alias DestroyFun = void function(ref Alloc alloc,ref T) nothrow; 66 private DestroyFun _fun; 67 @property void destroyFun(DestroyFun fun){_fun = fun;} 68 @property DestroyFun destroyFun(){return _fun;} 69 70 private void doDestroy(ref T d){ 71 if(_fun) 72 _fun(_alloc, d); 73 } 74 private void doDestroy(T[] d){ 75 if(_fun) { 76 for(size_t i = 0; i < d.length; ++i) 77 _fun(_alloc, d[i]); 78 } 79 } 80 } else { 81 this(this) 82 { 83 Data.inf(_data); 84 static if(hasElaborateAssign!T) 85 doCOW(0); 86 } 87 } 88 89 ~this() 90 { 91 Data.deInf(_alloc, _data); 92 } 93 94 void append(S)(auto ref S value) if(is(S : InsertT) || is(S : InsertT[])) 95 { 96 this.opOpAssign!("~",S)(value); 97 } 98 99 alias insertBack = append; 100 alias put = append; 101 alias pushBack = append; 102 103 size_t removeBack(size_t howMany = 1) { 104 if(howMany == 0 ) 105 return 0; 106 if (howMany >= _array.length) { 107 size_t len = _array.length; 108 clear(); 109 return len; 110 } 111 auto size = _array.length - howMany; 112 doInitVaule(_array[size .. $]); 113 _array = _array[0 .. size]; 114 return howMany; 115 } 116 117 void removeSite(size_t site) 118 in { 119 assert(site < _array.length); 120 } body{ 121 doCOW(0); 122 const size_t len = _array.length - 1; 123 doInitVaule(_array[site]); 124 for (size_t i = site; i < len; ++i) { 125 memcpy(&(_array[i]), &(_array[i + 1]), T.sizeof); 126 } 127 T v = T.init; 128 memcpy(&(_array[len]), &v, T.sizeof); 129 _array = _array[0..len]; 130 } 131 132 bool removeOne(S)(auto ref S value) if(is(Unqual!S == T)) { 133 doCOW(0); 134 for (size_t i = 0; i < _array.length; ++i) { 135 if (_array[i] == value) { 136 removeSite(i); 137 return true; 138 } 139 } 140 return false; 141 } 142 143 size_t removeAny(S)(auto ref S value) if(is(Unqual!S == T)) { 144 doCOW(0); 145 size_t rm = 0; 146 size_t site = 0; 147 for (size_t j = site; j < _array.length; ++j) { 148 if (_array[j] != value) { 149 if(site != j) 150 memcpy(&_array[site], &_array[j], T.sizeof); 151 site++; 152 } else { 153 doInitVaule(_array[j]); 154 rm++; 155 } 156 } 157 if(rm > 0) { 158 auto size = _array.length - rm; 159 auto rmed = _array[size .. $]; 160 _array = _array[0..size]; 161 fillWithMemcpy(rmed, T.init); 162 } 163 return rm; 164 } 165 166 alias removeIndex = removeSite; 167 168 void clear(){ 169 if(_data !is null && _data.count > 1){ 170 Data.deInf(_alloc,_data); 171 _data = null; 172 } else { 173 doInitVaule(_array); 174 } 175 _array = null; 176 } 177 178 void opIndexAssign(S)(auto ref S value,size_t index) if(is(Unqual!S == T)) 179 in{ 180 assert(index < _array.length); 181 }body{ 182 doCOW(0); 183 _array[index] = value; 184 } 185 186 auto opIndex(size_t index) const 187 in{ 188 assert(index < _array.length); 189 } body{ 190 return _array[index]; 191 } 192 193 auto opIndex(size_t index) 194 in{ 195 assert(index < _array.length); 196 } body{ 197 return _array[index]; 198 } 199 200 bool opEquals(S)(S other) const 201 if(is(S == Unqual!(typeof(this))) || is(S : InsertT[])) 202 { 203 if(_array.length == other.length){ 204 for(size_t i = 0; i < _array.length; ++ i) { 205 if(_array[i] != other[i]) 206 return false; 207 } 208 return true; 209 } else 210 return false; 211 } 212 213 size_t opDollar(){return _array.length;} 214 215 void opAssign(S)(auto ref S n) if((is(S == Unqual!(typeof(this))) && !(isNotCopy)) || is(S : InsertT[])) 216 { 217 static if(is(S : InsertT[])){ 218 assign(n); 219 } else { 220 if(n._data !is _data){ 221 Data.deInf(_alloc,_data); 222 _data = n._data; 223 Data.inf(_data); 224 } 225 _array = n._array; 226 static if(hasElaborateAssign!T) 227 doCOW(0); 228 } 229 } 230 231 @property bool empty() const nothrow { 232 return _array.length == 0; 233 } 234 235 @property size_t length()const nothrow {return _array.length;} 236 237 int opApply(scope int delegate(ref T) dg) 238 { 239 int result = 0; 240 241 for (size_t i = 0; i < _array.length; i++) 242 { 243 result = dg(_array[i]); 244 if (result) 245 break; 246 } 247 return result; 248 } 249 250 int opApply(scope int delegate(size_t, ref T) dg) 251 { 252 int result = 0; 253 254 for (size_t i = 0; i < _array.length; i++) 255 { 256 result = dg(i, _array[i]); 257 if (result) break; 258 } 259 return result; 260 } 261 static if(!isNotCopy) { 262 @property typeof(this) dup() { 263 typeof(this) ret = this; 264 if(this._data !is null) 265 ret.doCOW(0); 266 return ret; 267 } 268 T[] idup(){ 269 return _array.dup; 270 } 271 } 272 273 immutable (T)[] opCast(C)() nothrow 274 if(is(C == immutable (T)[])) 275 { 276 return data(); 277 } 278 279 immutable (T)[] data() nothrow 280 { 281 return cast(immutable (T)[])_array; 282 } 283 284 @property const(T) * ptr() const nothrow{ 285 return _array.ptr; 286 } 287 288 typeof(this) opBinary(string op,S)(auto ref S other) 289 if((is(S == Unqual!(typeof(this))) || is(S : InsertT[])) && op == "~") 290 { 291 typeof(this) ret = this; 292 ret ~= other; 293 return ret; 294 } 295 296 void opOpAssign(string op,S)(auto ref S other) 297 if((is(S == Unqual!(typeof(this))) || is(S : InsertT[]) || is(S : InsertT)) && op == "~") 298 { 299 static if(is(Unqual!S == T)){ 300 const size_t tmpLength = 1; 301 } else { 302 if(other.length == 0) return; 303 const size_t tmpLength = other.length; 304 } 305 doCOW(tmpLength); 306 T * tptr = _data.data.ptr + _array.length; 307 static if(is(Unqual!S == T)){ 308 tptr[0] = other; 309 } else { 310 memcpy(tptr, other.ptr, (tmpLength * T.sizeof)); 311 } 312 tptr = _data.data.ptr; 313 size_t len = _array.length + tmpLength; 314 _array = tptr[0..len]; 315 } 316 317 void reserve(size_t elements) { 318 if(elements < _array.length) 319 removeBack(_array.length - elements); 320 else if(elements > _array.length) 321 doCOW(elements - _array.length); 322 } 323 324 private: 325 void assign(S)(S[] input) if(is(S : InsertT)) 326 { 327 clear(); 328 if(input.length == 0) return; 329 auto data = buildData(); 330 Data.deInf(_alloc,data); 331 _data.reserve(input.length); 332 assign(_data.data.ptr,input); 333 _array = _data.data[0..input.length]; 334 } 335 336 pragma(inline) 337 void assign(S)(T * array,S[] data)if(is(S : InsertT)) 338 { 339 static if(hasElaborateAssign!T){ 340 for(size_t i = 0; i < data.length; ++i) 341 array[i] = data[i]; 342 } else { 343 memcpy(array, data.ptr, (data.length * T.sizeof)); 344 } 345 } 346 347 void doCOW(size_t tmpLength = 0) 348 { 349 auto data = buildData(); 350 if(data !is null) { 351 _data.reserve(extenSize(tmpLength)); 352 if(_array.length > 0){ 353 assign(_data.data.ptr, _array); 354 _array = _data.data[0.. _array.length]; 355 } 356 Data.deInf(_alloc,data); 357 } else if(tmpLength > 0 && _data.reserve(extenSize(tmpLength))) { 358 _array = _data.data[0.. _array.length]; 359 } 360 } 361 362 Data * buildData(){ 363 Data* data = null; 364 if(_data !is null && _data.count > 1){ 365 data = _data; 366 _data = null; 367 } 368 if(_data is null) { 369 _data = Data.allocate(_alloc); 370 static if(!StaticAlloc!Allocator) 371 _data._alloc = _alloc; 372 } 373 return data; 374 } 375 376 size_t extenSize(size_t size) { 377 size += _array.length; 378 if (size > 0) 379 size = size > 128 ? size + ((size / 3) * 2) : size * 2; 380 else 381 size = 32; 382 return size; 383 } 384 385 void doInitVaule(ref T v) 386 { 387 static if(isNotCopy){ 388 doDestroy(v); 389 } else static if(needDestroy) { 390 destroy(v); 391 } 392 T tv = T.init; 393 memcpy(&v,&tv,T.sizeof); 394 } 395 396 void doInitVaule(T[] v){ 397 for(size_t i = 0; i < v.length; ++i) 398 doInitVaule(v[i]); 399 } 400 401 402 private: 403 Data* _data; 404 T[] _array; 405 } 406 407 unittest { 408 import std.stdio; 409 import std.experimental.allocator.mallocator; 410 import std.experimental.allocator; 411 412 Vector!(int) vec; // = Vector!int(5); 413 int[] aa = [0, 1, 2, 3, 4, 5, 6, 7]; 414 vec.insertBack(aa); 415 assert(vec.length == 8); 416 417 vec.insertBack(10); 418 assert(vec.length == 9); 419 420 Vector!(int) vec21; 421 vec21 ~= 15; 422 vec21 ~= vec; 423 assert(vec21.length == 10); 424 425 assert(vec21.data == [15, 0, 1, 2, 3, 4, 5, 6, 7, 10]); 426 427 vec21[1] = 500; 428 assert(vec21.data == [15, 500, 1, 2, 3, 4, 5, 6, 7, 10]); 429 430 vec21.removeBack(); 431 assert(vec21.length == 9); 432 assert(vec21.data == [15, 500, 1, 2, 3, 4, 5, 6, 7]); 433 434 vec21.removeBack(3); 435 assert(vec21.length == 6); 436 assert(vec21.data == [15, 500, 1, 2, 3, 4]); 437 438 vec21.insertBack(aa); 439 assert(vec21.data == [15, 500, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7]); 440 441 vec21.removeSite(1); 442 assert(vec21.data == [15, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7]); 443 444 vec21.removeOne(1); 445 assert(vec21.data == [15, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7]); 446 447 vec21.removeAny(2); 448 assert(vec21.data == [15, 3, 4, 0, 1, 3, 4, 5, 6, 7]); 449 450 Vector!(ubyte[], Mallocator) vec2; 451 vec2.insertBack(cast(ubyte[]) "hahaha"); 452 vec2.insertBack(cast(ubyte[]) "huhuhu"); 453 assert(vec2.length == 2); 454 assert(cast(string) vec2[0] == "hahaha"); 455 assert(cast(string) vec2[1] == "huhuhu"); 456 457 Vector!(int, IAllocator) vec22 = Vector!(int, IAllocator)(allocatorObject(Mallocator.instance)); 458 int[] aa22 = [0, 1, 2, 3, 4, 5, 6, 7]; 459 vec22.insertBack(aa22); 460 assert(vec22.length == 8); 461 462 vec22.insertBack(10); 463 assert(vec22.length == 9); 464 465 vec22.insertBack(aa22); 466 vec22.insertBack([0, 1, 2, 1, 212, 1215, 1545, 1212, 154, 51515, 1545, 467 1545, 1241, 51, 45, 1215, 12415, 12415, 1545, 12415, 1545, 152415, 468 1541515, 15415, 1545, 1545, 1545, 1545, 15454, 0, 54154]); 469 470 vec22 ~= [0, 1, 2, 1, 212]; 471 immutable(int)[] dt = cast(immutable(int)[])vec22; 472 assert(dt.length == vec22.length); 473 //Vector!(shared int) vec2; 474 }