Skip to content

Commit

Permalink
Fix issue 10165 (rework of PR #1302)
Browse files Browse the repository at this point in the history
http://issues.dlang.org/show_bug.cgi?id=10165
Issue 10165: No syntax to create thread-local shared variables

Adds `UnqualRef` templated alias/struct that is similar to Rebindable but
strips away all qualifiers completely (including shared)
  • Loading branch information
Dicebot committed Aug 21, 2014
1 parent 82dc45e commit 4924d9a
Showing 1 changed file with 99 additions and 34 deletions.
133 changes: 99 additions & 34 deletions std/typecons.d
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,48 @@ unittest
static assert(!isTuple!(S));
}

// used by both Rebindable and UnqualRef
private mixin template RebindableCommon(T, U, alias This)
if (is(T == class) || is(T == interface))
{
private union
{
T original;
U stripped;
}

void opAssign(T another) @trusted pure nothrow
{
stripped = cast(U) another;
}

void opAssign(typeof(this) another) @trusted pure nothrow
{
stripped = another.stripped;
}

static if (is(T == const U) && is(T == const shared U))
{
// safely assign immutable to const / const shared
void opAssign(This!(immutable U) another) @trusted pure nothrow
{
stripped = another.stripped;
}
}

this(T initializer) @safe pure nothrow
{
opAssign(initializer);
}

@property ref inout(T) get() @trusted inout pure nothrow
{
return original;
}


alias get this;
}

/**
$(D Rebindable!(T)) is a simple, efficient wrapper that behaves just
Expand Down Expand Up @@ -1088,7 +1130,7 @@ risks usually associated with $(D cast).
*/
template Rebindable(T) if (is(T == class) || is(T == interface) || isDynamicArray!T)
{
static if (!is(T X == const U, U) && !is(T X == immutable U, U))
static if (!is(T == const U, U) && !is(T == immutable U, U))
{
alias Rebindable = T;
}
Expand All @@ -1100,39 +1142,7 @@ template Rebindable(T) if (is(T == class) || is(T == interface) || isDynamicArra
{
struct Rebindable
{
private union
{
T original;
U stripped;
}
void opAssign(T another) @trusted pure nothrow
{
stripped = cast(U) another;
}
void opAssign(Rebindable another) @trusted pure nothrow
{
stripped = another.stripped;
}
static if (is(T == const U))
{
// safely assign immutable to const
void opAssign(Rebindable!(immutable U) another) @trusted pure nothrow
{
stripped = another.stripped;
}
}

this(T initializer) @safe pure nothrow
{
opAssign(initializer);
}

@property ref inout(T) get() @trusted inout pure nothrow
{
return original;
}

alias get this;
mixin RebindableCommon!(T, U, Rebindable);
}
}
}
Expand Down Expand Up @@ -1242,6 +1252,61 @@ unittest
static assert(!__traits(compiles, Rebindable!(const int[1])));
}

/**
Similar to $(D Rebindable!(T)) but strips all qualifiers from the reference as
opposed to just constness / immutability. Primary intended use case is with
shared (having thread-local reference to shared class data)
*/
template UnqualRef(T)
if (is(T == class) || is(T == interface))
{
static if (!is(T == const U, U)
&& !is(T == immutable U, U)
&& !is(T == shared U, U)
&& !is(T == const shared U, U))
{
alias UnqualRef = T;
}
else
{
struct UnqualRef
{
mixin RebindableCommon!(T, U, UnqualRef);
}
}
}

///
unittest
{
class Data {}

static shared(Data) a;
static UnqualRef!(shared Data) b;

import core.thread;

auto thread = new core.thread.Thread({
a = new shared Data();
b = new shared Data();
});

thread.start();
thread.join();

assert(a !is null);
assert(b is null);
}

unittest
{
class C { }
alias T = UnqualRef!(const shared C);
static assert (is(typeof(T.stripped) == C));
}



/**
Order the provided members to minimize size while preserving alignment.
Returns a declaration to be mixed in.
Expand Down

0 comments on commit 4924d9a

Please sign in to comment.