Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #2195 from n8sh/core-hash-18918
Browse files Browse the repository at this point in the history
Fix Issue 18918 - core.internal.hash should perform memberwise hashing of structs with references
merged-on-behalf-of: Sebastian Wilzbach <sebi.wilzbach@gmail.com>
  • Loading branch information
dlang-bot committed Jul 2, 2018
2 parents 0e77501 + 22a6f7f commit 63efdef
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
11 changes: 7 additions & 4 deletions src/core/internal/convert.d
Expand Up @@ -603,15 +603,18 @@ nothrow pure @safe unittest
enum ctfe_works = (() => { Month x = Month.jan; return toUbyte(x).length > 0; })();
}

private bool isNonReference(T)()
package(core.internal) bool isNonReference(T)()
{
static if (is(T == struct) || is(T == union))
{
return isNonReferenceStruct!T();
}
else static if (__traits(isStaticArray, T))
{
return isNonReference!(typeof(T.init[0]))();
static if (T.length > 0)
return isNonReference!(typeof(T.init[0]))();
else
return true;
}
else static if (is(T E == enum))
{
Expand All @@ -637,9 +640,9 @@ private bool isNonReference(T)()

private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union))
{
foreach (cur; T.init.tupleof)
static foreach (cur; T.tupleof)
{
static if (!isNonReference!(typeof(cur))()) return false;
if (!isNonReference!(typeof(cur))()) return false;
}

return true;
Expand Down
22 changes: 21 additions & 1 deletion src/core/internal/hash.d
Expand Up @@ -43,9 +43,11 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati
{
alias ElementType = typeof(val[0]);
static if (is(ElementType == interface) || is(ElementType == class) ||
(is(ElementType == struct) && !isNonReference!ElementType) ||
((is(ElementType == struct) || is(ElementType == union))
&& is(typeof(val[0].toHash()) == size_t)))
//class or interface array or struct array with toHash(); CTFE depend on toHash() method
//also do this for arrays of structs whose hashes would be calculated in a memberwise fashion
{
size_t hash = seed;
foreach (o; val)
Expand Down Expand Up @@ -135,7 +137,15 @@ size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && (is(T ==
pragma(msg, "Warning: struct "~__traits(identifier, T)~" has method toHash, however it cannot be called with "~T.stringof~" this.");
}

static if (is(typeof(toUbyte(val)) == const(ubyte)[]))//CTFE ready for structs without reference fields
static if (is(T == struct) && !isNonReference!T) // Memberwise hashing.
{
static foreach (i, F; typeof(val.tupleof))
{
seed = hashOf(val.tupleof[i], seed);
}
return seed;
}
else static if (is(typeof(toUbyte(val)) == const(ubyte)[]))//CTFE ready for structs without reference fields
{
return bytesHash(toUbyte(val), seed);
}
Expand Down Expand Up @@ -446,6 +456,16 @@ unittest // issue 15111
testAlias!(int[8]);
}

nothrow pure @system unittest // issue 18918
{
static struct S { string array; }
auto s1 = S("abc");
auto s2 = S(s1.array.idup);
assert(hashOf(s1) == hashOf(s2));
enum e = hashOf(S("abc"));
assert(hashOf(s1) == e);
}

// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.

Expand Down

0 comments on commit 63efdef

Please sign in to comment.