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

Commit 63efdef

Browse files
authored
Merge pull request #2195 from n8sh/core-hash-18918
Fix Issue 18918 - core.internal.hash should perform memberwise hashing of structs with references merged-on-behalf-of: Sebastian Wilzbach <sebi.wilzbach@gmail.com>
2 parents 0e77501 + 22a6f7f commit 63efdef

File tree

2 files changed

+28
-5
lines changed

2 files changed

+28
-5
lines changed

src/core/internal/convert.d

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -603,15 +603,18 @@ nothrow pure @safe unittest
603603
enum ctfe_works = (() => { Month x = Month.jan; return toUbyte(x).length > 0; })();
604604
}
605605

606-
private bool isNonReference(T)()
606+
package(core.internal) bool isNonReference(T)()
607607
{
608608
static if (is(T == struct) || is(T == union))
609609
{
610610
return isNonReferenceStruct!T();
611611
}
612612
else static if (__traits(isStaticArray, T))
613613
{
614-
return isNonReference!(typeof(T.init[0]))();
614+
static if (T.length > 0)
615+
return isNonReference!(typeof(T.init[0]))();
616+
else
617+
return true;
615618
}
616619
else static if (is(T E == enum))
617620
{
@@ -637,9 +640,9 @@ private bool isNonReference(T)()
637640

638641
private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union))
639642
{
640-
foreach (cur; T.init.tupleof)
643+
static foreach (cur; T.tupleof)
641644
{
642-
static if (!isNonReference!(typeof(cur))()) return false;
645+
if (!isNonReference!(typeof(cur))()) return false;
643646
}
644647

645648
return true;

src/core/internal/hash.d

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati
4343
{
4444
alias ElementType = typeof(val[0]);
4545
static if (is(ElementType == interface) || is(ElementType == class) ||
46+
(is(ElementType == struct) && !isNonReference!ElementType) ||
4647
((is(ElementType == struct) || is(ElementType == union))
4748
&& is(typeof(val[0].toHash()) == size_t)))
4849
//class or interface array or struct array with toHash(); CTFE depend on toHash() method
50+
//also do this for arrays of structs whose hashes would be calculated in a memberwise fashion
4951
{
5052
size_t hash = seed;
5153
foreach (o; val)
@@ -135,7 +137,15 @@ size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && (is(T ==
135137
pragma(msg, "Warning: struct "~__traits(identifier, T)~" has method toHash, however it cannot be called with "~T.stringof~" this.");
136138
}
137139

138-
static if (is(typeof(toUbyte(val)) == const(ubyte)[]))//CTFE ready for structs without reference fields
140+
static if (is(T == struct) && !isNonReference!T) // Memberwise hashing.
141+
{
142+
static foreach (i, F; typeof(val.tupleof))
143+
{
144+
seed = hashOf(val.tupleof[i], seed);
145+
}
146+
return seed;
147+
}
148+
else static if (is(typeof(toUbyte(val)) == const(ubyte)[]))//CTFE ready for structs without reference fields
139149
{
140150
return bytesHash(toUbyte(val), seed);
141151
}
@@ -446,6 +456,16 @@ unittest // issue 15111
446456
testAlias!(int[8]);
447457
}
448458

459+
nothrow pure @system unittest // issue 18918
460+
{
461+
static struct S { string array; }
462+
auto s1 = S("abc");
463+
auto s2 = S(s1.array.idup);
464+
assert(hashOf(s1) == hashOf(s2));
465+
enum e = hashOf(S("abc"));
466+
assert(hashOf(s1) == e);
467+
}
468+
449469
// MurmurHash3 was written by Austin Appleby, and is placed in the public
450470
// domain. The author hereby disclaims copyright to this source code.
451471

0 commit comments

Comments
 (0)