1 /++ 2 $(H1 Thread-safe reference-counted context implementation). 3 +/ 4 module mir.rc.context; 5 6 import mir.type_info; 7 8 /++ 9 +/ 10 struct mir_rc_context 11 { 12 /// 13 extern (C) void function(mir_rc_context*) @system nothrow @nogc pure deallocator; 14 /// 15 immutable(mir_type_info)* typeInfo; 16 /// 17 shared size_t counter; 18 /// 19 size_t length; 20 } 21 22 /++ 23 Increase counter by 1. 24 25 Params: 26 context = shared_ptr context (not null) 27 +/ 28 export extern(C) 29 void mir_rc_increase_counter(ref mir_rc_context context) @system nothrow @nogc pure 30 { 31 import core.atomic: atomicOp; 32 with(context) 33 { 34 if (counter) 35 { 36 counter.atomicOp!"+="(1); 37 } 38 } 39 } 40 41 /++ 42 Decrease counter by 1. 43 Destroys data if counter decreased from 1 to 0. 44 45 Params: 46 context = shared_ptr context (not null) 47 +/ 48 export extern(C) 49 void mir_rc_decrease_counter(ref mir_rc_context context) @system nothrow @nogc pure 50 { 51 pragma(inline, true); 52 import core.atomic: atomicOp; 53 with(context) 54 { 55 if (counter) 56 { 57 if (counter.atomicOp!"-="(1) == 0) 58 { 59 mir_rc_delete(context); 60 } 61 } 62 // else 63 // { 64 // assert(0); 65 // } 66 } 67 } 68 69 /++ 70 +/ 71 export extern(C) 72 void mir_rc_delete(ref mir_rc_context context) 73 @system nothrow @nogc pure 74 { 75 assert(context.deallocator); 76 with(context) 77 { 78 with(typeInfo) 79 { 80 if (destructor) 81 { 82 auto ptr = cast(void*)(&context + 1); 83 auto i = length; 84 assert(i); 85 do 86 { 87 destructor(ptr); 88 ptr += size; 89 } 90 while(--i); 91 } 92 } 93 } 94 if (context.counter) 95 assert(0); 96 version (mir_secure_memory) 97 { 98 (cast(ubyte*)(&context + 1))[0 .. context.length * context.typeInfo.size] = 0; 99 } 100 context.deallocator(&context); 101 } 102 103 /++ 104 +/ 105 export extern(C) 106 mir_rc_context* mir_rc_create( 107 ref immutable(mir_type_info) typeInfo, 108 size_t length, 109 scope const void* payload = null, 110 bool initialize = true, 111 bool deallocate = true, 112 ) @system nothrow @nogc pure 113 { 114 import mir.internal.memory: malloc, free; 115 import core.stdc.string: memset, memcpy; 116 117 assert(length); 118 auto size = length * typeInfo.size; 119 auto fullSize = mir_rc_context.sizeof + size; 120 if (auto p = malloc(fullSize)) 121 { 122 version (mir_secure_memory) 123 { 124 (cast(ubyte*)p)[0 .. fullSize] = 0; 125 } 126 auto context = cast(mir_rc_context*)p; 127 context.deallocator = &free; 128 context.typeInfo = &typeInfo; 129 context.counter = deallocate; 130 context.length = length; 131 132 if (initialize) 133 { 134 auto ptr = cast(void*)(context + 1); 135 if (payload) 136 { 137 switch(typeInfo.size) 138 { 139 case 1: 140 memset(ptr, *cast(ubyte*)payload, size); 141 break; 142 case 2: 143 (cast(ushort*)ptr)[0 .. length] = *cast(ushort*)payload; 144 break; 145 case 4: 146 (cast(uint*)ptr)[0 .. length] = *cast(uint*)payload; 147 break; 148 case 8: 149 (cast(ulong*)ptr)[0 .. length] = *cast(ulong*)payload; 150 break; 151 static if (is(ucent)) 152 { 153 case 16: 154 (cast(ucent*)ptr)[0 .. length] = *cast(ucent*)payload; 155 break; 156 } 157 default: 158 foreach(i; 0 .. length) 159 { 160 memcpy(ptr, payload, typeInfo.size); 161 ptr += typeInfo.size; 162 } 163 } 164 } 165 else 166 { 167 memset(ptr, 0, size); 168 } 169 } 170 return context; 171 } 172 return null; 173 } 174 175 /// 176 package mixin template CommonRCImpl() 177 { 178 /// 179 ThisTemplate!(const T) lightConst()() return scope const @nogc nothrow @trusted @property 180 { return *cast(typeof(return)*) &this; } 181 182 /// ditto 183 ThisTemplate!(immutable T) lightImmutable()() return scope immutable @nogc nothrow @trusted @property 184 { return *cast(typeof(return)*) &this; } 185 186 /// 187 ThisTemplate!(const Unqual!T) moveToConst()() return scope @nogc nothrow @trusted @property 188 { 189 import core.lifetime: move; 190 return move(*cast(typeof(return)*) &this); 191 } 192 193 /// 194 pragma(inline, true) 195 size_t _counter() @trusted scope pure nothrow @nogc const @property 196 { 197 return cast(bool)this ? context.counter : 0; 198 } 199 200 /// 201 C opCast(C)() const 202 if (is(Unqual!C == bool)) 203 { 204 return _thisPtr !is null; 205 } 206 207 /// 208 ref C opCast(C : ThisTemplate!Q, Q)() pure nothrow @nogc @trusted 209 if (isImplicitlyConvertible!(T*, Q*)) 210 { 211 return *cast(typeof(return)*)&this; 212 } 213 214 /// ditto 215 C opCast(C : ThisTemplate!Q, Q)() pure nothrow @nogc const @trusted 216 if (isImplicitlyConvertible!(const(T)*, Q*)) 217 { 218 return *cast(typeof(return)*)&this; 219 } 220 221 /// ditto 222 C opCast(C : ThisTemplate!Q, Q)() pure nothrow @nogc immutable @trusted 223 if (isImplicitlyConvertible!(immutable(T)*, Q*)) 224 { 225 return *cast(typeof(return)*)&this; 226 } 227 228 /// ditto 229 C opCast(C : ThisTemplate!Q, Q)() pure nothrow @nogc const @system 230 if (isImplicitlyConvertible!(immutable(T)*, Q*) && !isImplicitlyConvertible!(const(T)*, Q*)) 231 { 232 return *cast(typeof(return)*)&this; 233 } 234 }