1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.collection.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 hunt.collection.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 }