Enum member atomicRcCode

A string that can be mixed-in a class declaration to implement IAtomicRefCounted. dispose is not implemented of course, but is called by release while the object is locked. Classes implementing it are free to do it in a non-thread safe manner as long as dispose does not manipulate external state.

enum atomicRcCode = "\x0a\x0a import std.typecons : Flag, Yes;\x0a import std.traits : Unqual;\x0a\x0a debug {\x0a ~this() {\x0a // no gc operation allowed during gc pass\x0a import std.stdio : stderr;\x0a enum phrase = rcTypeName ~ \" was not properly disposed\\n\";\x0a if (refCount != 0) {\x0a stderr.write(phrase);\x0a stderr.flush();\x0a }\x0a }\x0a enum rcTypeName = Unqual!(typeof(this)).stringof;\x0a }\x0a\x0a debug(rc) {\x0a private final shared void rcDebug(Args...)(string fmt, Args args)\x0a {\x0a import gfx.core.rc : gfxRcLog, rcPrintStack, rcTypeRegex;\x0a import gfx.core.util : StackTrace;\x0a import std.algorithm : min;\x0a import std.regex : matchFirst;\x0a\x0a if (!matchFirst(rcTypeName, rcTypeRegex)) return;\x0a\x0a gfxRcLog.debugf(fmt, args);\x0a if (rcPrintStack) {\x0a const st = StackTrace.obtain(13, StackTrace.Options.all);\x0a const frames = st.frames.length > 2 ? st.frames[2 .. $] : [];\x0a foreach (i, f; frames) {\x0a gfxRcLog.debugf(\" %02d %s\", i, f.symbol);\x0a }\x0a }\x0a }\x0a }\x0a\x0a\x0a public final shared override @property size_t refCountShared() const\x0a {\x0a import core.atomic : atomicLoad;\x0a return atomicLoad(_refCount);\x0a }\x0a\x0a public final shared override void retainShared()\x0a {\x0a import core.atomic : atomicOp;\x0a const rc = atomicOp!\"+=\"(_refCount, 1);\x0a debug(rc) {\x0a rcDebug(\"retain %s: %s -> %s\", rcTypeName, rc-1, rc);\x0a }\x0a }\x0a\x0a public final shared override bool releaseShared(in Flag!\"disposeOnZero\" disposeOnZero = Yes.disposeOnZero)\x0a {\x0a import core.atomic : atomicOp;\x0a const rc = atomicOp!\"-=\"(_refCount, 1);\x0a\x0a debug(rc) {\x0a rcDebug(\"release %s: %s -> %s\", rcTypeName, rc+1, rc);\x0a }\x0a if (rc == 0 && disposeOnZero) {\x0a debug(rc) {\x0a rcDebug(\"dispose %s\", rcTypeName);\x0a }\x0a synchronized(this) {\x0a // cast shared away\x0a auto obj = cast(Unqual!(typeof(this)))this;\x0a obj.dispose();\x0a }\x0a return true;\x0a }\x0a else {\x0a return false;\x0a }\x0a }\x0a\x0a public final shared override bool rcLockShared()\x0a {\x0a import core.atomic : atomicLoad, cas;\x0a while (1) {\x0a const c = atomicLoad(_refCount);\x0a\x0a if (c == 0) {\x0a debug(rc) {\x0a rcDebug(\"rcLock %s: %s\", rcTypeName, c);\x0a }\x0a return false;\x0a }\x0a if (cas(&_refCount, c, c+1)) {\x0a debug(rc) {\x0a rcDebug(\"rcLock %s: %s\", rcTypeName, c+1);\x0a }\x0a return true;\x0a }\x0a }\x0a }\x0a\x0a private size_t _refCount=0;\x0a";