1 /**
2 Utility and ancillary artifacts of `stdx.collections`.
3 */
4 module stdx.collections.common;
5 import std.range: isInputRange;
6 
7 auto tail(Collection)(Collection collection)
8     if (isInputRange!Collection)
9 {
10     collection.popFront();
11     return collection;
12 }
13 
14 struct Mutable(T)
15 {
16     import std.experimental.allocator : IAllocator, theAllocator, dispose;
17     import std.experimental.allocator.building_blocks.affix_allocator;
18     import core.atomic : atomicOp;
19 
20     private struct RefCountedMutable
21     {
22         IAllocator _alloc;
23         T _payload;
24         size_t _rc;
25     }
26 
27     private void[] _mutableSupport;
28     private AffixAllocator!(IAllocator, RefCountedMutable) _mutableAllocator;
29 
30     this(this _)(T theMutable)
31     {
32         this(theAllocator, theMutable);
33     }
34 
35     this(this _)(IAllocator alloc, T theMutable)
36     {
37         auto t = AffixAllocator!(IAllocator, RefCountedMutable)(alloc);
38         auto tSupport = (() @trusted => t.allocate(1))();
39         () @trusted {
40             t.prefix(tSupport)._alloc = alloc;
41             t.prefix(tSupport)._payload = theMutable;
42         }();
43         _mutableSupport = (() @trusted => cast(typeof(_mutableSupport))(tSupport))();
44         _mutableAllocator = (() @trusted => cast(typeof(_mutableAllocator))(t))();
45     }
46 
47     this(this) @trusted
48     {
49         if (_mutableSupport !is null)
50         {
51             addRef(_mutableAllocator, _mutableSupport);
52         }
53     }
54 
55     @trusted void addRef(AllocQual, SupportQual, this Qualified)(AllocQual alloc, SupportQual support)
56     {
57         assert(support !is null);
58         static if (is(Qualified == immutable) || is(Qualified == const))
59         {
60             auto p = cast(shared uint*)(&alloc.prefix(support)._rc);
61             atomicOp!"+="(*p, 1);
62         }
63         else
64         {
65             ++alloc.prefix(support)._rc;
66         }
67     }
68 
69     ~this() @trusted
70     {
71         if (_mutableSupport !is null)
72         {
73             if (_mutableAllocator.prefix(_mutableSupport)._rc == 0)
74             {
75                 auto origAlloc = _mutableAllocator.prefix(_mutableSupport)._alloc;
76                 auto disposer = AffixAllocator!(IAllocator, RefCountedMutable)(origAlloc);
77                 disposer.dispose(_mutableSupport);
78             }
79             else
80             {
81                 --_mutableAllocator.prefix(_mutableSupport)._rc;
82             }
83         }
84     }
85 
86     auto ref opAssign()(auto ref typeof(this) rhs)
87     {
88         if (rhs._mutableSupport !is null
89             && _mutableSupport is rhs._mutableSupport)
90         {
91             return this;
92         }
93         if (rhs._mutableSupport !is null)
94         {
95             //() @trusted {
96                 //++rhs._mutableAllocator.prefix(rhs._mutableSupport)._rc;
97             //}();
98             addRef(rhs._mutableAllocator, rhs._mutableSupport);
99         }
100         __dtor();
101         _mutableSupport = rhs._mutableSupport;
102         _mutableAllocator = rhs._mutableAllocator;
103         return this;
104     }
105 
106     bool isNull(this _)()
107     {
108         return _mutableSupport is null;
109     }
110 
111     auto ref get(this Q)()
112     {
113         static if (is(Q == immutable) || is(Q == const))
114         {
115             alias PayloadType = typeof(_mutableAllocator.prefix(_mutableSupport)._payload);
116             return cast(shared PayloadType)(_mutableAllocator.prefix(_mutableSupport)._payload);
117         }
118         else
119         {
120             return _mutableAllocator.prefix(_mutableSupport)._payload;
121         }
122     }
123 
124     void set(T v)
125     {
126         _mutableAllocator.prefix(_mutableSupport)._payload = v;
127     }
128 }