1 module rc.allocator;
2 
3 import std.experimental.allocator;
4 import std.experimental.allocator.mallocator;
5 import std.experimental.allocator.building_blocks.affix_allocator;
6 
7 static this() { RC.affixObj = allocatorObject(RC.affix); }
8 
9 ///
10 struct RC
11 {
12 static:
13     ///
14     alias affix = AffixAllocator!(Mallocator,size_t,size_t).instance;
15     ///
16     IAllocator affixObj;
17 
18     ///
19     auto make(T,A...)( auto ref A args )
20     { return incRef( affixObj.make!T(args) ); }
21 
22     ///
23     T[] makeArray(T,A...)( size_t length )
24     { return incRef( affixObj.makeArray!T(length) ); }
25 
26     ///
27     T[] makeArray(T,A...)( size_t length, auto ref T init )
28     { return incRef( affixObj.makeArray!T(length,init) ); }
29 
30     ///
31     private void dispose(T)( T* p ) { affixObj.dispose(p); }
32 
33     ///
34     private void dispose(T)( T p )
35         if( is(T == class) || is(T == interface) )
36     { affixObj.dispose(p); }
37 
38     ///
39     private void dispose(T)( T[] arr ) { affixObj.dispose(arr); }
40 
41     ///
42     ref size_t refCount(T)( T p )
43         if( is(T == class) || is(T == interface) )
44     { return affix.prefix( (cast(void*)p)[0..__traits(classInstanceSize,T)] ); }
45 
46     ///
47     ref size_t refCount(T)( T* p )
48     { return affix.prefix( (cast(void*)p)[0..T.sizeof] ); }
49 
50     ///
51     ref size_t refCount(T)( T[] arr )
52     { return affix.prefix( cast(void[])arr ); }
53 
54     ///
55     auto incRef(T)( auto ref T p )
56     {
57         if( p is null ) return null;
58         refCount(p)++;
59         return p;
60     }
61 
62     ///
63     auto decRef(T)( T p )
64     {
65         if( p is null ) return null;
66 
67         if( refCount(p) > 0 )
68         {
69             refCount(p)--;
70             if( refCount(p) == 0 )
71             {
72                 dispose(p);
73                 return null;
74             }
75         }
76 
77         return p;
78     }
79 }
80 
81 unittest
82 {
83     auto p = RC.make!int( 10 );
84     assert( is( typeof(p) == int* ) );
85     assert( *p == 10 );
86     assert( RC.refCount(p) == 1 );
87     p = RC.decRef(p);
88     assert( p is null );
89 }
90 
91 unittest
92 {
93     static int inc = 0;
94 
95     static class A
96     {
97         this() { inc = 5; }
98         ~this() { inc = 2; }
99     }
100 
101     assert( inc == 0 );
102     auto a = RC.make!A();
103     assert( RC.refCount(a) == 1 );
104     auto b = a;
105     assert( RC.refCount(a) == 1 );
106     RC.incRef(b);
107     assert( RC.refCount(a) == 2 );
108     assert( RC.refCount(b) == 2 );
109     assert( inc == 5 );
110     a = RC.decRef(a);
111     assert( inc == 5 );
112     assert( a !is null );
113     a = RC.decRef(a);
114     assert( inc == 2 );
115     assert( a is null );
116 }