1 module yu.memory.scopedref;
2 
3 import std.experimental.allocator;
4 import std.traits : isPointer;
5 
6 import yu.traits : Pointer;
7 
8 struct IScopedRef(Allocator, T) {
9     alias ValueType = Pointer!T;
10     enum isSaticAlloc = (stateSize!Allocator == 0);
11     static if (isSaticAlloc)
12         alias Alloc = typeof(Allocator.instance);
13     else
14         alias Alloc = Allocator;
15     alias Deleter = void function(ref Alloc, ValueType);
16 
17     static if (isSaticAlloc) {
18         this(ValueType ptr) {
19             this(ptr, &defaultDeleter);
20         }
21 
22         this(ValueType ptr, Deleter deleter) {
23             _d = ptr;
24             resetDeleter(deleter);
25         }
26     } else {
27         this(Alloc alloc, ValueType ptr) {
28             this(alloc, ptr, &defaultDeleter);
29         }
30 
31         this(Alloc alloc, ValueType ptr, Deleter deleter) {
32             _alloc = alloc;
33             _d = ptr;
34             resetDeleter(deleter);
35         }
36 
37         @property Alloc allocator() nothrow {
38             return _alloc;
39         }
40     }
41 
42     ~this() {
43         release();
44     }
45 
46     void swap(typeof(this) other) {
47         static import std.algorithm.mutation;
48 
49         std.algorithm.mutation.swap(other._d, this._d);
50         std.algorithm.mutation.swap(other._deleter, this._deleter);
51         static if (!isSaticAlloc)
52             std.algorithm.mutation.swap(other._alloc, this._alloc);
53     }
54 
55     @property ValueType data() {
56         return _d;
57     }
58 
59     alias data this;
60 
61     bool isNull() nothrow {
62         return (_d is null);
63     }
64 
65     void resetDeleter(Deleter dele)
66     in {
67         assert(dele, "Deleter Function must be not null");
68     }
69     body {
70         _deleter = dele;
71     }
72 
73     void reset(ValueType v) {
74         release();
75         _d = v;
76     }
77 
78     static if (isSaticAlloc) {
79         void reset(ValueType v, Alloc alloc) {
80             release();
81             _alloc = alloc;
82             _d = v;
83         }
84     }
85 
86     static if (isPointer!ValueType) {
87         ref T opUnary(string op)() if (op == "*") {
88             return *_d;
89         }
90     }
91 
92     ValueType take() nothrow {
93         ValueType ret = _d;
94         _d = null;
95         return ret;
96     }
97 
98     void release() {
99         if (_d && _deleter) {
100             _deleter(_alloc, _d);
101         }
102         _d = null;
103         _deleter = &defaultDeleter;
104     }
105 
106     @disable this(this);
107 private:
108     static void defaultDeleter(ref Alloc alloc, ValueType value) {
109         alloc.dispose(value);
110     }
111 
112     ValueType _d;
113     static if (!isSaticAlloc)
114         Alloc _alloc;
115     else
116         alias _alloc = Alloc.instance;
117     Deleter _deleter = &defaultDeleter;
118 }