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