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 }