1 module yu.container.common; 2 3 import core.atomic; 4 import std.traits : Unqual; 5 import std.experimental.allocator; 6 7 8 template StaticAlloc(ALLOC) 9 { 10 enum StaticAlloc = (stateSize!ALLOC == 0); 11 } 12 13 mixin template AllocDefine(ALLOC) 14 { 15 static if (StaticAlloc!ALLOC) { 16 alias _alloc = ALLOC.instance; 17 alias Alloc = typeof(ALLOC.instance); 18 } else { 19 alias Alloc = ALLOC; 20 private ALLOC _alloc; 21 public @property ALLOC allocator() { 22 return _alloc; 23 } 24 } 25 } 26 27 struct RefCount 28 { 29 pragma(inline) 30 uint refCnt() shared nothrow @nogc 31 { 32 return atomicOp!("+=")(_count, 1); 33 } 34 35 pragma(inline) 36 uint derefCnt() shared nothrow @nogc 37 { 38 return atomicOp!("-=")(_count, 1); 39 } 40 41 pragma(inline) 42 uint count() shared nothrow @nogc 43 { 44 return atomicLoad(_count); 45 } 46 47 private: 48 shared uint _count = 1; 49 } 50 51 mixin template Refcount() 52 { 53 static typeof(this) * allocate(ALLOC)(auto ref ALLOC alloc){ 54 return alloc.make!(typeof(this))(); 55 } 56 57 static void deallocate(ALLOC)(auto ref ALLOC alloc, typeof(this) * dd){ 58 alloc.dispose(dd); 59 } 60 61 static void inf(typeof(this) * dd) 62 { 63 if(dd is null) return; 64 dd._count.refCnt(); 65 } 66 67 static typeof(this) * deInf(ALLOC)(auto ref ALLOC alloc, typeof(this) * dd) 68 { 69 if(dd is null) return dd; 70 if(dd._count.derefCnt() == 0){ 71 deallocate!ALLOC(alloc,dd); 72 return null; 73 } 74 return dd; 75 } 76 @property uint count(){return _count.count();} 77 @disable this(this); 78 private shared RefCount _count; 79 } 80 81 /// Array Cow Data 82 struct ArrayCOWData(T, Allocator,bool inGC = false) if(is(T == Unqual!T)) 83 { 84 import core.memory : GC; 85 import std.exception : enforce; 86 import core.stdc.string : memcpy; 87 import yu.array : fillWithMemcpy; 88 89 ~this() 90 { 91 destoryBuffer(); 92 } 93 94 bool reserve(size_t elements) { 95 if (elements <= data.length) 96 return false; 97 size_t len = _alloc.goodAllocSize(elements * T.sizeof); 98 elements = len / T.sizeof; 99 void[] varray = _alloc.allocate(len); 100 auto ptr = cast(T*) enforce(varray.ptr); 101 size_t bleng = (data.length * T.sizeof); 102 if (data.length > 0) { 103 memcpy(ptr, data.ptr, bleng); 104 } 105 varray = varray[bleng.. len]; 106 fillWithMemcpy!T(varray,T.init); 107 static if(inGC){ 108 GC.addRange(ptr, len); 109 } 110 destoryBuffer(); 111 data = ptr[0 .. elements]; 112 return true; 113 } 114 115 pragma(inline, true) 116 void destoryBuffer(){ 117 if (data.ptr) { 118 static if(inGC) 119 GC.removeRange(data.ptr); 120 _alloc.deallocate(data); 121 } 122 } 123 124 static if (StaticAlloc!Allocator) 125 alias _alloc = Allocator.instance; 126 else 127 Allocator _alloc; 128 T[] data; 129 130 mixin Refcount!(); 131 }