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 }