Add TaggedUnion.toHash.
Allows using TaggedUnions as associative array keys.
This commit is contained in:
parent
2875f53c1d
commit
bde8e6eeff
|
@ -108,6 +108,13 @@ struct TaggedAlgebraic(U) if (is(U == union) || is(U == struct) || is(U == enum)
|
|||
@property auto ref opDispatch(this TA, ARGS...)(auto ref ARGS args) if (hasOp!(TA, OpKind.field, name, ARGS) && !hasOp!(TA, OpKind.method, name, ARGS)) { return implementOp!(OpKind.field, name)(this, args); }
|
||||
}
|
||||
|
||||
static if (is(typeof(m_union.toHash()))) {
|
||||
size_t toHash()
|
||||
const @safe nothrow {
|
||||
return m_union.toHash();
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables equality comparison with the stored value.
|
||||
auto ref opEquals(T, this TA)(auto ref T other)
|
||||
if (is(Unqual!T == TaggedAlgebraic) || hasOp!(TA, OpKind.binary, "==", T))
|
||||
|
@ -1390,3 +1397,17 @@ unittest {
|
|||
auto ta = TA(12);
|
||||
static assert(!is(typeof(ta.put(12))));
|
||||
}
|
||||
|
||||
@safe nothrow unittest {
|
||||
struct TU { int i; string s; }
|
||||
alias TA = TaggedAlgebraic!TU;
|
||||
|
||||
static assert(is(typeof(TA.init.toHash()) == size_t));
|
||||
|
||||
int[TA] aa;
|
||||
aa[TA(1)] = 1;
|
||||
aa[TA("foo")] = 2;
|
||||
|
||||
assert(aa[TA(1)] == 1);
|
||||
assert(aa[TA("foo")] == 2);
|
||||
}
|
||||
|
|
|
@ -202,6 +202,26 @@ align(commonAlignment!(UnionKindTypes!(UnionFieldEnum!U))) struct TaggedUnion
|
|||
assert(false); // never reached
|
||||
}
|
||||
|
||||
static if (allSatisfy!(isHashable, FieldTypes))
|
||||
{
|
||||
/// Enables using a tagged union value as an associative array key.
|
||||
size_t toHash()
|
||||
const @safe nothrow {
|
||||
size_t ret;
|
||||
final switch (m_kind) {
|
||||
foreach (i, tname; fieldNames) {
|
||||
alias T = FieldTypes[i];
|
||||
case __traits(getMember, Kind, tname):
|
||||
static if (!isUnitType!T) {
|
||||
ret = hashOf(trustedGet!T);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret ^ (m_kind * 0xBA7A57E3);
|
||||
}
|
||||
}
|
||||
|
||||
/// The type ID of the currently stored value.
|
||||
@property Kind kind() const { return m_kind; }
|
||||
|
||||
|
@ -547,6 +567,20 @@ unittest { // support trailing underscores properly
|
|||
assert(val.intValue == 20);
|
||||
}
|
||||
|
||||
@safe nothrow unittest {
|
||||
static struct S { int i; string s; }
|
||||
alias TU = TaggedUnion!S;
|
||||
|
||||
static assert(is(typeof(TU.init.toHash()) == size_t));
|
||||
|
||||
int[TU] aa;
|
||||
aa[TU(1)] = 1;
|
||||
aa[TU("foo")] = 2;
|
||||
|
||||
assert(aa[TU(1)] == 1);
|
||||
assert(aa[TU("foo")] == 2);
|
||||
}
|
||||
|
||||
|
||||
@property auto forceNothrowPostblit()
|
||||
{
|
||||
|
@ -733,6 +767,14 @@ unittest {
|
|||
}
|
||||
}
|
||||
|
||||
private template isHashable(T)
|
||||
{
|
||||
static if (isUnitType!T) enum isHashable = true;
|
||||
else static if (__traits(compiles, (ref const(T) val) @safe nothrow => hashOf(val)))
|
||||
enum isHashable = true;
|
||||
else enum isHashable = false;
|
||||
}
|
||||
|
||||
package void rawEmplace(T)(void[] dst, ref T src)
|
||||
{
|
||||
T[] tdst = () @trusted { return cast(T[])dst[0 .. T.sizeof]; } ();
|
||||
|
|
Loading…
Reference in a new issue