libphobos: Apply core.internal.hash updates from druntime

Backported from upstream druntime 2.084

Reviewed-on: https://github.com/dlang/druntime/pull/2469

libphobos/ChangeLog:

	* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Remove rt/util/hash.d
	* libdruntime/Makefile.in: Rebuild.
	* testsuite/libphobos.aa/aa.exp: New file.
	* testsuite/libphobos.aa/test_aa.d: New test.
	* testsuite/libphobos.hash/hash.exp: New file.
	* testsuite/libphobos.hash/test_hash.d: New test.

From-SVN: r268754
This commit is contained in:
Iain Buclaw 2019-02-10 21:01:24 +00:00 committed by Iain Buclaw
parent f1b7b50aff
commit e613d99266
50 changed files with 2647 additions and 1385 deletions

View File

@ -1,3 +1,12 @@
2019-02-10 Iain Buclaw <ibuclaw@gdcproject.org>
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Remove rt/util/hash.d
* libdruntime/Makefile.in: Rebuild.
* testsuite/libphobos.aa/aa.exp: New file.
* testsuite/libphobos.aa/test_aa.d: New test.
* testsuite/libphobos.hash/hash.exp: New file.
* testsuite/libphobos.hash/test_hash.d: New test.
2019-01-12 Iain Buclaw <ibuclaw@gdcproject.org>
* README.gcc: New file.

View File

@ -1,4 +1,4 @@
f2db21937e650553066c30f1a9d5a7d08a1b3573
cc215408bbdbc3324a95080aeef31287f663e57c
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.

View File

@ -197,8 +197,8 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
rt/typeinfo/ti_ucent.d rt/typeinfo/ti_uint.d rt/typeinfo/ti_ulong.d \
rt/typeinfo/ti_ushort.d rt/typeinfo/ti_void.d rt/typeinfo/ti_wchar.d \
rt/util/array.d rt/util/container/array.d rt/util/container/common.d \
rt/util/container/hashtab.d rt/util/container/treap.d rt/util/hash.d \
rt/util/random.d rt/util/typeinfo.d rt/util/utf.d
rt/util/container/hashtab.d rt/util/container/treap.d rt/util/random.d \
rt/util/typeinfo.d rt/util/utf.d
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d

View File

@ -229,8 +229,7 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
rt/typeinfo/ti_wchar.lo rt/util/array.lo \
rt/util/container/array.lo rt/util/container/common.lo \
rt/util/container/hashtab.lo rt/util/container/treap.lo \
rt/util/hash.lo rt/util/random.lo rt/util/typeinfo.lo \
rt/util/utf.lo
rt/util/random.lo rt/util/typeinfo.lo rt/util/utf.lo
am__objects_2 = gc/bits.lo gc/config.lo gc/gcinterface.lo \
gc/impl/conservative/gc.lo gc/impl/manual/gc.lo gc/os.lo \
gc/pooltable.lo gc/proxy.lo
@ -831,8 +830,8 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
rt/typeinfo/ti_ucent.d rt/typeinfo/ti_uint.d rt/typeinfo/ti_ulong.d \
rt/typeinfo/ti_ushort.d rt/typeinfo/ti_void.d rt/typeinfo/ti_wchar.d \
rt/util/array.d rt/util/container/array.d rt/util/container/common.d \
rt/util/container/hashtab.d rt/util/container/treap.d rt/util/hash.d \
rt/util/random.d rt/util/typeinfo.d rt/util/utf.d
rt/util/container/hashtab.d rt/util/container/treap.d rt/util/random.d \
rt/util/typeinfo.d rt/util/utf.d
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/exception.d \
core/stdcpp/typeinfo.d
@ -1256,7 +1255,6 @@ rt/util/container/array.lo: rt/util/container/$(am__dirstamp)
rt/util/container/common.lo: rt/util/container/$(am__dirstamp)
rt/util/container/hashtab.lo: rt/util/container/$(am__dirstamp)
rt/util/container/treap.lo: rt/util/container/$(am__dirstamp)
rt/util/hash.lo: rt/util/$(am__dirstamp)
rt/util/random.lo: rt/util/$(am__dirstamp)
rt/util/typeinfo.lo: rt/util/$(am__dirstamp)
rt/util/utf.lo: rt/util/$(am__dirstamp)

View File

@ -33,7 +33,7 @@ private ubyte[] ctfe_alloc()(size_t n)
}
}
@trusted pure nothrow
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqual!T == double) || is(Unqual!T == real) ||
is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal))
{
@ -72,7 +72,7 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqua
ulong mantissa2 = parsed.mantissa2;
off_bytes--; // go back one, since mantissa only stored data in 56
// bits, ie 7 bytes
for(; off_bytes < FloatTraits!T.MANTISSA/8; ++off_bytes)
for (; off_bytes < FloatTraits!T.MANTISSA/8; ++off_bytes)
{
buff[off_bytes] = cast(ubyte)mantissa2;
mantissa2 >>= 8;
@ -114,13 +114,13 @@ const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == float) || is(Unqua
}
}
@safe pure nothrow
@safe pure nothrow @nogc
private Float parse(bool is_denormalized = false, T)(T x) if (is(Unqual!T == ifloat) || is(Unqual!T == idouble) || is(Unqual!T == ireal))
{
return parse(x.im);
}
@safe pure nothrow
@safe pure nothrow @nogc
private Float parse(bool is_denormalized = false, T:real)(T x_) if (floatFormat!T != FloatFormat.Real80)
{
Unqual!T x = x_;
@ -178,7 +178,7 @@ private Float parse(bool is_denormalized = false, T:real)(T x_) if (floatFormat!
}
}
@safe pure nothrow
@safe pure nothrow @nogc
private Float parse(bool _ = false, T:real)(T x_) if (floatFormat!T == FloatFormat.Real80)
{
Unqual!T x = x_;
@ -291,10 +291,10 @@ private template FloatTraits(T) if (floatFormat!T == FloatFormat.Quadruple)
}
@safe pure nothrow
@safe pure nothrow @nogc
private real binPow2(int pow)
{
static real binPosPow2(int pow) @safe pure nothrow
static real binPosPow2(int pow) @safe pure nothrow @nogc
{
assert(pow > 0);
@ -319,14 +319,14 @@ private real binPow2(int pow)
//Need in CTFE, because CTFE float and double expressions computed more precisely that run-time expressions.
@safe pure nothrow
@safe pure nothrow @nogc
private ulong shiftrRound(ulong x)
{
return (x >> 1) + (x & 1);
}
@safe pure nothrow
private uint binLog2(T)(T x)
@safe pure nothrow @nogc
private uint binLog2(T)(const T x)
{
assert(x > 0);
int max = 2 ^^ (FloatTraits!T.EXPONENT-1)-1;
@ -353,7 +353,7 @@ private uint binLog2(T)(T x)
return max;
}
@safe pure nothrow
@safe pure nothrow @nogc
private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == FloatFormat.Real80)
{
x *= 2.0L^^FloatTraits!T.MANTISSA;
@ -362,7 +362,7 @@ private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == Float
return Float(fl.mantissa >> pow, 0, sign);
}
@safe pure nothrow
@safe pure nothrow @nogc
private Float denormalizedMantissa(T)(T x, uint sign)
if (floatFormat!T == FloatFormat.Float || floatFormat!T == FloatFormat.Double)
{
@ -372,7 +372,7 @@ private Float denormalizedMantissa(T)(T x, uint sign)
return Float(shiftrRound(mant), 0, sign);
}
@safe pure nothrow
@safe pure nothrow @nogc
private Float denormalizedMantissa(T)(T x, uint sign) if (floatFormat!T == FloatFormat.Quadruple)
{
x *= 2.0L^^FloatTraits!T.MANTISSA;
@ -568,21 +568,35 @@ template floatFormat(T) if (is(T:real) || is(T:ireal))
}
// all toUbyte functions must be evaluable at compile time
@trusted pure nothrow
const(ubyte)[] toUbyte(T)(T[] arr) if (T.sizeof == 1)
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const T[] arr) if (T.sizeof == 1)
{
return cast(const(ubyte)[])arr;
}
@trusted pure nothrow
const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyte)[])) && (T.sizeof > 1))
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const T[] arr) if (T.sizeof > 1)
{
if (__ctfe)
{
const(ubyte)[] ret;
foreach (cur; arr)
ubyte[] ret = ctfe_alloc(T.sizeof * arr.length);
static if (is(T EType == enum)) // Odd style is to avoid template instantiation in most cases.
alias E = OriginalType!EType;
else
alias E = T;
static if (is(E == struct) || is(E == union) || __traits(isStaticArray, E) || !is(typeof(arr[0] is null)))
{
ret ~= toUbyte(cur);
size_t offset = 0;
foreach (ref cur; arr)
{
ret[offset .. offset + T.sizeof] = toUbyte(cur)[0 .. T.sizeof];
offset += T.sizeof;
}
}
else
{
foreach (cur; arr)
assert(cur is null, "Unable to compute byte representation of non-null pointer at compile time");
}
return ret;
}
@ -592,14 +606,16 @@ const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyt
}
}
@trusted pure nothrow
const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enum))
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (__traits(isIntegral, T) && !is(T == enum) && !is(T == __vector))
{
static if (T.sizeof == 1)
{
if (__ctfe)
{
return cast(const(ubyte)[])[val];
ubyte[] result = ctfe_alloc(1);
result[0] = cast(ubyte) val;
return result;
}
else
{
@ -608,7 +624,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
}
else if (__ctfe)
{
ubyte[T.sizeof] tmp;
ubyte[] tmp = ctfe_alloc(T.sizeof);
Unqual!T val_ = val;
for (size_t i = 0; i < T.sizeof; ++i)
{
@ -618,7 +634,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
tmp[idx] = cast(ubyte)(val_&0xff);
val_ >>= 8;
}
return tmp[].dup;
return tmp;
}
else
{
@ -626,14 +642,41 @@ const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enu
}
}
@trusted pure nothrow
const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal))
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == __vector))
{
if (!__ctfe)
return (cast(const ubyte*) &val)[0 .. T.sizeof];
else static if (is(typeof(val[0]) : void))
assert(0, "Unable to compute byte representation of " ~ T.stringof ~ " at compile time.");
else
{
// This code looks like it should work in CTFE but it segfaults:
// auto a = val.array;
// return toUbyte(a);
alias E = typeof(val[0]);
ubyte[] result = ctfe_alloc(T.sizeof);
for (size_t i = 0, j = 0; i < T.sizeof; i += E.sizeof, ++j)
{
result[i .. i + E.sizeof] = toUbyte(val[j]);
}
return result;
}
}
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T == cdouble) ||is(Unqual!T == creal))
{
if (__ctfe)
{
auto re = val.re;
auto im = val.im;
return (re.toUbyte() ~ im.toUbyte());
auto a = re.toUbyte();
auto b = im.toUbyte();
ubyte[] result = ctfe_alloc(a.length + b.length);
result[0 .. a.length] = a[0 .. a.length];
result[a.length .. $] = b[0 .. b.length];
return result;
}
else
{
@ -641,14 +684,13 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(Unqual!T == cfloat) || is(Unqual!T =
}
}
@trusted pure nothrow
const(ubyte)[] toUbyte(T)(ref T val) if (is(T == enum) && is(typeof(toUbyte(cast(V)val)) == const(ubyte)[]))
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == enum))
{
if (__ctfe)
{
static if (is(T V == enum)){}
V e_val = val;
return toUbyte(e_val);
return toUbyte(cast(const V) val);
}
else
{
@ -656,76 +698,65 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(T == enum) && is(typeof(toUbyte(cast
}
}
private bool isNonReference(T)()
nothrow pure @safe unittest
{
static if (is(T == struct) || is(T == union))
{
return isNonReferenceStruct!T();
}
else static if (__traits(isStaticArray, T))
{
return isNonReference!(typeof(T.init[0]))();
}
else static if (is(T E == enum))
{
return isNonReference!(E)();
}
else static if (!__traits(isScalar, T))
{
return false;
}
else static if (is(T V : V*))
{
return false;
}
else static if (is(T == function))
{
return false;
}
else
{
return true;
}
// Issue 19008 - check toUbyte works on enums.
enum Month : uint { jan = 1}
Month m = Month.jan;
const bytes = toUbyte(m);
enum ctfe_works = (() => { Month x = Month.jan; return toUbyte(x).length > 0; })();
}
private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union))
{
foreach (cur; T.init.tupleof)
{
static if (!isNonReference!(typeof(cur))()) return false;
}
return true;
}
@trusted pure nothrow
const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union))
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == delegate) || is(T : V*, V) && __traits(getAliasThis, T).length == 0)
{
if (__ctfe)
{
ubyte[T.sizeof] bytes;
foreach (key, cur; val.tupleof)
{
alias CUR_TYPE = typeof(cur);
static if (isNonReference!(CUR_TYPE)())
{
bytes[val.tupleof[key].offsetof .. val.tupleof[key].offsetof + cur.sizeof] = toUbyte(cur)[];
}
else static if (is(typeof(val.tupleof[key] is null)))
{
assert(val.tupleof[key] is null, "Unable to compute byte representation of non-null reference field at compile time");
//skip, because val bytes are zeros
}
else
{
//pragma(msg, "is null: ", typeof(CUR_TYPE).stringof);
assert(0, "Unable to compute byte representation of "~typeof(CUR_TYPE).stringof~" field at compile time");
}
}
return bytes[].dup;
if (val !is null) assert(0, "Unable to compute byte representation of non-null pointer at compile time");
return ctfe_alloc(T.sizeof);
}
else
{
return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
}
}
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(const ref T val) if (is(T == struct) || is(T == union))
{
if (__ctfe)
{
ubyte[] bytes = ctfe_alloc(T.sizeof);
foreach (key, ref cur; val.tupleof)
{
static if (is(typeof(cur) EType == enum)) // Odd style is to avoid template instantiation in most cases.
alias CurType = OriginalType!EType;
else
alias CurType = typeof(cur);
static if (is(CurType == struct) || is(CurType == union) || __traits(isStaticArray, CurType) || !is(typeof(cur is null)))
{
bytes[val.tupleof[key].offsetof .. val.tupleof[key].offsetof + CurType.sizeof] = toUbyte(cur)[];
}
else
{
assert(cur is null, "Unable to compute byte representation of non-null reference field at compile time");
//skip, because val bytes are zeros
}
}
return bytes;
}
else
{
return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
}
}
// Strips off all `enum`s from type `T`.
// Perhaps move to core.internal.types.
private template OriginalType(T)
{
static if (is(T EType == enum))
alias OriginalType = .OriginalType!EType;
else
alias OriginalType = T;
}

File diff suppressed because it is too large Load Diff

View File

@ -128,6 +128,30 @@ template dtorIsNothrow(T)
enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow);
}
/*
Tests whether all given items satisfy a template predicate, i.e. evaluates to
$(D F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1])).
*/
package(core.internal)
template allSatisfy(alias F, T...)
{
static if (T.length == 0)
{
enum allSatisfy = true;
}
else static if (T.length == 1)
{
enum allSatisfy = F!(T[0]);
}
else
{
static if (allSatisfy!(F, T[0 .. $/2]))
enum allSatisfy = allSatisfy!(F, T[$/2 .. $]);
else
enum allSatisfy = false;
}
}
template anySatisfy(alias F, T...)
{
static if (T.length == 0)

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@ private:
return used - deleted;
}
@property size_t dim() const pure nothrow @nogc
@property size_t dim() const pure nothrow @nogc @safe
{
return buckets.length;
}
@ -183,7 +183,7 @@ private pure nothrow @nogc:
return hash == HASH_DELETED;
}
@property bool filled() const
@property bool filled() const @safe
{
return cast(ptrdiff_t) hash < 0;
}
@ -365,8 +365,29 @@ extern (C) size_t _aaLen(in AA aa) pure nothrow @nogc
* If key was not in the aa, a mutable pointer to newly inserted value which
* is set to all zeros
*/
extern (C) void* _aaGetY(AA* aa, const TypeInfo_AssociativeArray ti, in size_t valsz,
in void* pkey)
extern (C) void* _aaGetY(AA* aa, const TypeInfo_AssociativeArray ti,
in size_t valsz, in void* pkey)
{
bool found;
return _aaGetX(aa, ti, valsz, pkey, found);
}
/******************************
* Lookup *pkey in aa.
* Called only from implementation of require
* Params:
* aa = associative array opaque pointer
* ti = TypeInfo for the associative array
* valsz = ignored
* pkey = pointer to the key value
* found = true if the value was found
* Returns:
* if key was in the aa, a mutable pointer to the existing value.
* If key was not in the aa, a mutable pointer to newly inserted value which
* is set to all zeros
*/
extern (C) void* _aaGetX(AA* aa, const TypeInfo_AssociativeArray ti,
in size_t valsz, in void* pkey, out bool found)
{
// lazily alloc implementation
if (aa.impl is null)
@ -377,7 +398,10 @@ extern (C) void* _aaGetY(AA* aa, const TypeInfo_AssociativeArray ti, in size_t v
// found a value => return it
if (auto p = aa.findSlotLookup(hash, pkey, ti.key))
{
found = true;
return p.entry + aa.valoff;
}
auto p = aa.findSlotInsert(hash);
if (p.deleted)
@ -584,6 +608,7 @@ extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void
void* pkey = keys.ptr;
void* pval = vals.ptr;
immutable off = aa.valoff;
uint actualLength = 0;
foreach (_; 0 .. length)
{
immutable hash = calcHash(pkey, ti.key);
@ -595,6 +620,7 @@ extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void
p.hash = hash;
p.entry = allocEntry(aa, pkey); // move key, no postblit
aa.firstUsed = min(aa.firstUsed, cast(uint)(p - aa.buckets.ptr));
actualLength++;
}
else if (aa.entryTI && hasDtor(ti.value))
{
@ -608,7 +634,7 @@ extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void
pkey += keysz;
pval += valsz;
}
aa.used = cast(uint) length;
aa.used = actualLength;
return aa;
}
@ -653,6 +679,7 @@ extern (C) hash_t _aaGetHash(in AA* aa, in TypeInfo tiRaw) nothrow
auto uti = unqualify(tiRaw);
auto ti = *cast(TypeInfo_AssociativeArray*)&uti;
immutable off = aa.valoff;
auto keyHash = &ti.key.getHash;
auto valHash = &ti.value.getHash;
size_t h;
@ -660,10 +687,11 @@ extern (C) hash_t _aaGetHash(in AA* aa, in TypeInfo tiRaw) nothrow
{
if (!b.filled)
continue;
size_t[2] h2 = [b.hash, valHash(b.entry + off)];
// use XOR here, so that hash is independent of element order
h ^= hashOf(h2);
size_t[2] h2 = [keyHash(b.entry), valHash(b.entry + off)];
// use addition here, so that hash is independent of element order
h += hashOf(h2);
}
return h;
}
@ -677,7 +705,7 @@ struct Range
alias impl this;
}
extern (C) pure nothrow @nogc
extern (C) pure nothrow @nogc @safe
{
Range _aaRange(AA aa)
{
@ -694,21 +722,32 @@ extern (C) pure nothrow @nogc
bool _aaRangeEmpty(Range r)
{
return r.impl is null || r.idx == r.dim;
return r.impl is null || r.idx >= r.dim;
}
void* _aaRangeFrontKey(Range r)
{
assert(!_aaRangeEmpty(r));
if (r.idx >= r.dim)
return null;
return r.buckets[r.idx].entry;
}
void* _aaRangeFrontValue(Range r)
{
return r.buckets[r.idx].entry + r.valoff;
assert(!_aaRangeEmpty(r));
if (r.idx >= r.dim)
return null;
auto entry = r.buckets[r.idx].entry;
return entry is null ?
null :
(() @trusted { return entry + r.valoff; } ());
}
void _aaRangePopFront(ref Range r)
{
if (r.idx >= r.dim) return;
for (++r.idx; r.idx < r.dim; ++r.idx)
{
if (r.buckets[r.idx].filled)
@ -717,221 +756,7 @@ extern (C) pure nothrow @nogc
}
}
//==============================================================================
// Unittests
//------------------------------------------------------------------------------
pure nothrow unittest
{
int[string] aa;
assert(aa.keys.length == 0);
assert(aa.values.length == 0);
aa["hello"] = 3;
assert(aa["hello"] == 3);
aa["hello"]++;
assert(aa["hello"] == 4);
assert(aa.length == 1);
string[] keys = aa.keys;
assert(keys.length == 1);
assert(keys[0] == "hello");
int[] values = aa.values;
assert(values.length == 1);
assert(values[0] == 4);
aa.rehash;
assert(aa.length == 1);
assert(aa["hello"] == 4);
aa["foo"] = 1;
aa["bar"] = 2;
aa["batz"] = 3;
assert(aa.keys.length == 4);
assert(aa.values.length == 4);
foreach (a; aa.keys)
{
assert(a.length != 0);
assert(a.ptr != null);
}
foreach (v; aa.values)
{
assert(v != 0);
}
}
unittest // Test for Issue 10381
{
alias II = int[int];
II aa1 = [0 : 1];
II aa2 = [0 : 1];
II aa3 = [0 : 2];
assert(aa1 == aa2); // Passes
assert(typeid(II).equals(&aa1, &aa2));
assert(!typeid(II).equals(&aa1, &aa3));
}
pure nothrow unittest
{
string[int] key1 = [1 : "true", 2 : "false"];
string[int] key2 = [1 : "false", 2 : "true"];
string[int] key3;
// AA lits create a larger hashtable
int[string[int]] aa1 = [key1 : 100, key2 : 200, key3 : 300];
// Ensure consistent hash values are computed for key1
assert((key1 in aa1) !is null);
// Manually assigning to an empty AA creates a smaller hashtable
int[string[int]] aa2;
aa2[key1] = 100;
aa2[key2] = 200;
aa2[key3] = 300;
assert(aa1 == aa2);
// Ensure binary-independence of equal hash keys
string[int] key2a;
key2a[1] = "false";
key2a[2] = "true";
assert(aa1[key2a] == 200);
}
// Issue 9852
pure nothrow unittest
{
// Original test case (revised, original assert was wrong)
int[string] a;
a["foo"] = 0;
a.remove("foo");
assert(a == null); // should not crash
int[string] b;
assert(b is null);
assert(a == b); // should not deref null
assert(b == a); // ditto
int[string] c;
c["a"] = 1;
assert(a != c); // comparison with empty non-null AA
assert(c != a);
assert(b != c); // comparison with null AA
assert(c != b);
}
// Bugzilla 14104
unittest
{
import core.stdc.stdio;
alias K = const(ubyte)*;
size_t[K] aa;
immutable key = cast(K)(cast(size_t) uint.max + 1);
aa[key] = 12;
assert(key in aa);
}
unittest
{
int[int] aa;
foreach (k, v; aa)
assert(false);
foreach (v; aa)
assert(false);
assert(aa.byKey.empty);
assert(aa.byValue.empty);
assert(aa.byKeyValue.empty);
size_t n;
aa = [0 : 3, 1 : 4, 2 : 5];
foreach (k, v; aa)
{
n += k;
assert(k >= 0 && k < 3);
assert(v >= 3 && v < 6);
}
assert(n == 3);
n = 0;
foreach (v; aa)
{
n += v;
assert(v >= 3 && v < 6);
}
assert(n == 12);
n = 0;
foreach (k, v; aa)
{
++n;
break;
}
assert(n == 1);
n = 0;
foreach (v; aa)
{
++n;
break;
}
assert(n == 1);
}
unittest
{
int[int] aa;
assert(!aa.remove(0));
aa = [0 : 1];
assert(aa.remove(0));
assert(!aa.remove(0));
aa[1] = 2;
assert(!aa.remove(0));
assert(aa.remove(1));
assert(aa.length == 0);
assert(aa.byKey.empty);
}
// test zero sized value (hashset)
unittest
{
alias V = void[0];
auto aa = [0 : V.init];
assert(aa.length == 1);
assert(aa.byKey.front == 0);
assert(aa.byValue.front == V.init);
aa[1] = V.init;
assert(aa.length == 2);
aa[0] = V.init;
assert(aa.length == 2);
assert(aa.remove(0));
aa[0] = V.init;
assert(aa.length == 2);
assert(aa == [0 : V.init, 1 : V.init]);
}
// test tombstone purging
unittest
{
int[int] aa;
foreach (i; 0 .. 6)
aa[i] = i;
foreach (i; 0 .. 6)
assert(aa.remove(i));
foreach (i; 6 .. 10)
aa[i] = i;
assert(aa.length == 4);
foreach (i; 6 .. 10)
assert(i in aa);
}
// Most tests are now in in test_aa.d
// test postblit for AA literals
unittest
@ -982,34 +807,3 @@ unittest
GC.runFinalizers((cast(char*)(&entryDtor))[0 .. 1]);
assert(T.dtor == 6 && T.postblit == 2);
}
// for aa.clear
pure nothrow unittest
{
int[int] aa;
assert(aa.length == 0);
foreach (i; 0 .. 100)
aa[i] = i * 2;
assert(aa.length == 100);
auto aa2 = aa;
assert(aa2.length == 100);
aa.clear();
assert(aa.length == 0);
assert(aa2.length == 0);
aa2[5] = 6;
assert(aa.length == 1);
assert(aa[5] == 6);
}
// test AA as key (Issue 16974)
unittest
{
int[int] a = [1 : 2], a2 = [1 : 2];
assert([a : 3] == [a : 3]);
assert([a : 3] == [a2 : 3]);
assert(typeid(a).getHash(&a) == typeid(a).getHash(&a));
assert(typeid(a).getHash(&a) == typeid(a).getHash(&a2));
}

View File

@ -25,7 +25,7 @@ class TypeInfo_Ar : TypeInfo_Array
override string toString() const { return (F[]).stringof; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
return Array!F.hashOf(*cast(F[]*)p);
}

View File

@ -25,7 +25,7 @@ class TypeInfo_Aq : TypeInfo_Array
override string toString() const { return (F[]).stringof; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
return Array!F.hashOf(*cast(F[]*)p);
}

View File

@ -25,7 +25,7 @@ class TypeInfo_Ac : TypeInfo_Array
override string toString() const { return (F[]).stringof; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
return Array!F.hashOf(*cast(F[]*)p);
}

View File

@ -25,7 +25,7 @@ class TypeInfo_Ad : TypeInfo_Array
override string toString() const { return (F[]).stringof; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
return Array!F.hashOf(*cast(F[]*)p);
}

View File

@ -25,7 +25,7 @@ class TypeInfo_Af : TypeInfo_Array
override string toString() const { return (F[]).stringof; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
return Array!F.hashOf(*cast(F[]*)p);
}

View File

@ -14,7 +14,6 @@
module rt.typeinfo.ti_Ag;
private import core.stdc.string;
private import rt.util.hash;
private import core.internal.string;
// byte[]
@ -25,10 +24,10 @@ class TypeInfo_Ag : TypeInfo_Array
override string toString() const { return "byte[]"; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
const s = *cast(const void[]*)p;
return rt.util.hash.hashOf(s, 0);
return hashOf(s);
}
override bool equals(in void* p1, in void* p2) const
@ -118,54 +117,10 @@ class TypeInfo_Aa : TypeInfo_Ah
{
override string toString() const { return "char[]"; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
char[] s = *cast(char[]*)p;
size_t hash = 0;
version (all)
{
foreach (char c; s)
hash = hash * 11 + c;
}
else
{
size_t len = s.length;
char *str = s;
while (1)
{
switch (len)
{
case 0:
return hash;
case 1:
hash *= 9;
hash += *cast(ubyte *)str;
return hash;
case 2:
hash *= 9;
hash += *cast(ushort *)str;
return hash;
case 3:
hash *= 9;
hash += (*cast(ushort *)str << 8) +
(cast(ubyte *)str)[2];
return hash;
default:
hash *= 9;
hash += *cast(uint *)str;
str += 4;
len -= 4;
break;
}
}
}
return hash;
return hashOf(s);
}
override @property inout(TypeInfo) next() inout

View File

@ -14,7 +14,6 @@
module rt.typeinfo.ti_Aint;
private import core.stdc.string;
private import rt.util.hash;
extern (C) void[] _adSort(void[] a, TypeInfo ti);
@ -26,10 +25,11 @@ class TypeInfo_Ai : TypeInfo_Array
override string toString() const { return "int[]"; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
const s = *cast(const int[]*)p;
return rt.util.hash.hashOf(s, 0);
// Hash as if unsigned.
const s = *cast(const uint[]*)p;
return hashOf(s);
}
override bool equals(in void* p1, in void* p2) const

View File

@ -14,7 +14,6 @@
module rt.typeinfo.ti_Along;
private import core.stdc.string;
private import rt.util.hash;
// long[]
@ -24,10 +23,11 @@ class TypeInfo_Al : TypeInfo_Array
override string toString() const { return "long[]"; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
const s = *cast(const long[]*)p;
return rt.util.hash.hashOf(s, 0);
// Hash as if unsigned.
const s = *cast(const ulong[]*)p;
return hashOf(s);
}
override bool equals(in void* p1, in void* p2) const

View File

@ -25,7 +25,7 @@ class TypeInfo_Ae : TypeInfo_Array
override string toString() const { return (F[]).stringof; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
return Array!F.hashOf(*cast(F[]*)p);
}

View File

@ -14,7 +14,6 @@
module rt.typeinfo.ti_Ashort;
private import core.stdc.string;
private import rt.util.hash;
// short[]
@ -24,10 +23,11 @@ class TypeInfo_As : TypeInfo_Array
override string toString() const { return "short[]"; }
override size_t getHash(in void* p) @trusted const
override size_t getHash(scope const void* p) @trusted const
{
const s = *cast(const short[]*)p;
return rt.util.hash.hashOf(s, 0);
// Hash as if unsigned.
const s = *cast(const ushort[]*)p;
return hashOf(s);
}
override bool equals(in void* p1, in void* p2) const

View File

@ -22,7 +22,7 @@ class TypeInfo_C : TypeInfo
//pure:
//nothrow:
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
Object o = *cast(Object*)p;
return o ? o.toHash() : 0;

View File

@ -24,9 +24,9 @@ class TypeInfo_g : TypeInfo
override string toString() const pure nothrow @safe { return "byte"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(byte *)p;
return *cast(const byte *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -27,7 +27,7 @@ class TypeInfo_r : TypeInfo
override string toString() const { return F.stringof; }
override size_t getHash(in void* p) const @trusted
override size_t getHash(scope const void* p) const @trusted
{
return Floating!F.hashOf(*cast(F*)p);
}

View File

@ -13,8 +13,6 @@
*/
module rt.typeinfo.ti_cent;
private import rt.util.hash;
static if (is(cent)):
// cent
@ -28,9 +26,10 @@ class TypeInfo_zi : TypeInfo
override string toString() const pure nothrow @safe { return "cent"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return rt.util.hash.hashOf(p[0 .. cent.sizeof], 0);
// cent & ucent hash the same if ucent.sizeof >= size_t.sizeof.
return hashOf(*cast(const ucent*) p);
}
override bool equals(in void* p1, in void* p2)

View File

@ -27,7 +27,7 @@ class TypeInfo_q : TypeInfo
override string toString() const { return F.stringof; }
override size_t getHash(in void* p) const @trusted
override size_t getHash(scope const void* p) const @trusted
{
return Floating!F.hashOf(*cast(F*)p);
}

View File

@ -24,9 +24,9 @@ class TypeInfo_a : TypeInfo
override string toString() const pure nothrow @safe { return "char"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(char *)p;
return *cast(const char *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -27,7 +27,7 @@ class TypeInfo_c : TypeInfo
override string toString() const { return F.stringof; }
override size_t getHash(in void* p) const @trusted
override size_t getHash(scope const void* p) const @trusted
{
return Floating!F.hashOf(*cast(F*)p);
}

View File

@ -24,9 +24,9 @@ class TypeInfo_w : TypeInfo
override string toString() const pure nothrow @safe { return "dchar"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(dchar *)p;
return *cast(const dchar *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -13,7 +13,6 @@
*/
module rt.typeinfo.ti_delegate;
private import rt.util.hash;
// delegate
@ -26,9 +25,9 @@ class TypeInfo_D : TypeInfo
pure:
nothrow:
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return rt.util.hash.hashOf(p[0 .. dg.sizeof], 0);
return hashOf(*cast(dg*)p);
}
override bool equals(in void* p1, in void* p2)

View File

@ -27,7 +27,7 @@ class TypeInfo_d : TypeInfo
override string toString() const { return F.stringof; }
override size_t getHash(in void* p) const @trusted
override size_t getHash(scope const void* p) const @trusted
{
return Floating!F.hashOf(*cast(F*)p);
}

View File

@ -27,7 +27,7 @@ class TypeInfo_f : TypeInfo
override string toString() const { return F.stringof; }
override size_t getHash(in void* p) const @trusted
override size_t getHash(scope const void* p) const @trusted
{
return Floating!F.hashOf(*cast(F*)p);
}

View File

@ -24,9 +24,9 @@ class TypeInfo_i : TypeInfo
override string toString() const pure nothrow @safe { return "int"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(uint *)p;
return *cast(const int *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -13,8 +13,6 @@
*/
module rt.typeinfo.ti_long;
private import rt.util.hash;
// long
class TypeInfo_l : TypeInfo
@ -26,9 +24,13 @@ class TypeInfo_l : TypeInfo
override string toString() const pure nothrow @safe { return "long"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return rt.util.hash.hashOf(p[0 .. long.sizeof], 0);
static if (ulong.sizeof <= size_t.sizeof)
return *cast(const long*)p;
else
// long & ulong hash the same if ulong.sizeof > size_t.sizeof.
return hashOf(*cast(const ulong*)p);
}
override bool equals(in void* p1, in void* p2)

View File

@ -19,7 +19,7 @@ class TypeInfo_n : TypeInfo
{
override string toString() const @safe { return "typeof(null)"; }
override size_t getHash(in void* p) const
override size_t getHash(scope const void* p) const
{
return 0;
}

View File

@ -23,9 +23,10 @@ class TypeInfo_P : TypeInfo
pure:
nothrow:
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return cast(size_t)*cast(void**)p;
size_t addr = cast(size_t) *cast(const void**)p;
return addr ^ (addr >> 4);
}
override bool equals(in void* p1, in void* p2)

View File

@ -27,7 +27,7 @@ class TypeInfo_e : TypeInfo
override string toString() const { return F.stringof; }
override size_t getHash(in void* p) const @trusted
override size_t getHash(scope const void* p) const @trusted
{
return Floating!F.hashOf(*cast(F*)p);
}

View File

@ -24,9 +24,9 @@ class TypeInfo_s : TypeInfo
override string toString() const pure nothrow @safe { return "short"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(short *)p;
return *cast(const short *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -24,9 +24,9 @@ class TypeInfo_h : TypeInfo
override string toString() const pure nothrow @safe { return "ubyte"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(ubyte *)p;
return *cast(const ubyte *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -13,8 +13,6 @@
*/
module rt.typeinfo.ti_ucent;
private import rt.util.hash;
static if (is(ucent)):
// ucent
@ -28,9 +26,9 @@ class TypeInfo_zk : TypeInfo
override string toString() const pure nothrow @safe { return "ucent"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return rt.util.hash.hashOf(p[0 .. ucent.sizeof], 0);
return hashOf(*cast(const ucent*) p);
}
override bool equals(in void* p1, in void* p2)

View File

@ -24,9 +24,9 @@ class TypeInfo_k : TypeInfo
override string toString() const pure nothrow @safe { return "uint"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(uint *)p;
return *cast(const uint *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -13,7 +13,6 @@
*/
module rt.typeinfo.ti_ulong;
private import rt.util.hash;
// ulong
@ -26,9 +25,12 @@ class TypeInfo_m : TypeInfo
override string toString() const pure nothrow @safe { return "ulong"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return rt.util.hash.hashOf(p[0 .. ulong.sizeof], 0);
static if (ulong.sizeof <= size_t.sizeof)
return *cast(const ulong*)p;
else
return hashOf(*cast(const ulong*)p);
}
override bool equals(in void* p1, in void* p2)

View File

@ -24,9 +24,9 @@ class TypeInfo_t : TypeInfo
override string toString() const pure nothrow @safe { return "ushort"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(ushort *)p;
return *cast(const ushort *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -24,7 +24,7 @@ class TypeInfo_v : TypeInfo
override string toString() const pure nothrow @safe { return "void"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
assert(0);
}

View File

@ -24,9 +24,9 @@ class TypeInfo_u : TypeInfo
override string toString() { return "wchar"; }
override size_t getHash(in void* p)
override size_t getHash(scope const void* p)
{
return *cast(wchar *)p;
return *cast(const wchar *)p;
}
override bool equals(in void* p1, in void* p2)

View File

@ -146,11 +146,10 @@ private:
static hash_t hashOf(in ref Key key) @trusted
{
import rt.util.hash : hashOf;
static if (is(Key U : U[]))
return hashOf(key, 0);
return .hashOf(key, 0);
else
return hashOf((&key)[0 .. 1], 0);
return .hashOf((&key)[0 .. 1], 0);
}
@property hash_t mask() const

View File

@ -1,107 +0,0 @@
/**
* The default hash implementation.
*
* Copyright: Copyright Sean Kelly 2009 - 2016.
* License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Sean Kelly
* Source: $(DRUNTIMESRC src/rt/util/_hash.d)
*/
module rt.util.hash;
version (X86)
version = AnyX86;
version (X86_64)
version = AnyX86;
version (AnyX86)
version = HasUnalignedOps;
@trusted pure nothrow @nogc
size_t hashOf( const(void)[] buf, size_t seed )
{
/*
* This is Paul Hsieh's SuperFastHash algorithm, described here:
* http://www.azillionmonkeys.com/qed/hash.html
* It is protected by the following open source license:
* http://www.azillionmonkeys.com/qed/weblicense.html
*/
static uint get16bits( const (ubyte)* x ) pure nothrow @nogc
{
// CTFE doesn't support casting ubyte* -> ushort*, so revert to
// per-byte access when in CTFE.
version (HasUnalignedOps)
{
if (!__ctfe)
return *cast(ushort*) x;
}
return ((cast(uint) x[1]) << 8) + (cast(uint) x[0]);
}
// NOTE: SuperFastHash normally starts with a zero hash value. The seed
// value was incorporated to allow chaining.
auto data = cast(const(ubyte)*) buf.ptr;
auto len = buf.length;
auto hash = seed;
if ( len == 0 || data is null )
return 0;
int rem = len & 3;
len >>= 2;
for ( ; len > 0; len-- )
{
hash += get16bits( data );
auto tmp = (get16bits( data + 2 ) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * ushort.sizeof;
hash += hash >> 11;
}
switch ( rem )
{
case 3: hash += get16bits( data );
hash ^= hash << 16;
hash ^= data[ushort.sizeof] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits( data );
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
break;
default:
break;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
unittest
{
enum test_str = "Sample string";
size_t hashval = hashOf(test_str, 5);
//import core.stdc.stdio;
//printf("hashval = %lld\n", cast(long)hashval);
if (hashval.sizeof == 4)
assert(hashval == 528740845);
else if (hashval.sizeof == 8)
assert(hashval == 8106800467257150594L);
else
assert(0);
}

View File

@ -6,6 +6,7 @@
* Authors: Kenji Hara
*/
module rt.util.typeinfo;
static import core.internal.hash;
template Floating(T)
if (is(T == float) || is(T == double) || is(T == real))
@ -32,19 +33,7 @@ if (is(T == float) || is(T == double) || is(T == real))
return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
}
size_t hashOf(T value) @trusted
{
if (value == 0) // +0.0 and -0.0
value = 0;
static if (is(T == float)) // special case?
return *cast(uint*)&value;
else
{
import rt.util.hash;
return rt.util.hash.hashOf((&value)[0 .. 1], 0);
}
}
public alias hashOf = core.internal.hash.hashOf;
}
template Floating(T)
if (is(T == cfloat) || is(T == cdouble) || is(T == creal))
@ -73,13 +62,7 @@ if (is(T == cfloat) || is(T == cdouble) || is(T == creal))
return result;
}
size_t hashOf(T value) @trusted
{
if (value == 0 + 0i)
value = 0 + 0i;
import rt.util.hash;
return rt.util.hash.hashOf((&value)[0 .. 1], 0);
}
public alias hashOf = core.internal.hash.hashOf;
}
template Array(T)
@ -118,13 +101,7 @@ if (is(T == float) || is(T == double) || is(T == real) ||
return 0;
}
size_t hashOf(T[] value)
{
size_t h = 0;
foreach (e; value)
h += Floating!T.hashOf(e);
return h;
}
public alias hashOf = core.internal.hash.hashOf;
}
version (unittest)
@ -247,7 +224,7 @@ unittest
{
assert(f1 == 0 + 0i);
assert(f1 == f2);
assert(f1 == f2);
assert(f1 !is f2);
ti = typeid(F);
assert(ti.getHash(&f1) == ti.getHash(&f2));

View File

@ -0,0 +1,29 @@
# Copyright (C) 2018 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
load_lib libphobos-dg.exp
# Initialize dg.
dg-init
# Gather a list of all tests.
set tests [lsort [find $srcdir/$subdir *.d]]
# Main loop.
dg-runtest $tests "" $DEFAULT_DFLAGS
# All done.
dg-finish

View File

@ -0,0 +1,856 @@
void main()
{
testKeysValues1();
testKeysValues2();
testGet1();
testGet2();
testRequire1();
testRequire2();
testRequire3();
testUpdate1();
testUpdate2();
testByKey1();
testByKey2();
testByKey3();
testByKey4();
issue5842();
issue5842Expanded();
issue5925();
issue8583();
issue9052();
issue9119();
issue9852();
issue10381();
issue10720();
issue11761();
issue13078();
issue14104();
issue14626();
issue15290();
issue15367();
issue16974();
issue18071();
testIterationWithConst();
testStructArrayKey();
miscTests1();
miscTests2();
testRemove();
testZeroSizedValue();
testTombstonePurging();
testClear();
}
void testKeysValues1()
{
static struct T
{
byte b;
static size_t count;
this(this) { ++count; }
}
T[int] aa;
T t;
aa[0] = t;
aa[1] = t;
assert(T.count == 2);
auto vals = aa.values;
assert(vals.length == 2);
assert(T.count == 4);
T.count = 0;
int[T] aa2;
aa2[t] = 0;
assert(T.count == 1);
aa2[t] = 1;
assert(T.count == 1);
auto keys = aa2.keys;
assert(keys.length == 1);
assert(T.count == 2);
}
void testKeysValues2() nothrow pure
{
int[string] aa;
assert(aa.keys.length == 0);
assert(aa.values.length == 0);
aa["hello"] = 3;
assert(aa["hello"] == 3);
aa["hello"]++;
assert(aa["hello"] == 4);
assert(aa.length == 1);
string[] keys = aa.keys;
assert(keys.length == 1);
assert(keys[0] == "hello");
int[] values = aa.values;
assert(values.length == 1);
assert(values[0] == 4);
aa.rehash;
assert(aa.length == 1);
assert(aa["hello"] == 4);
aa["foo"] = 1;
aa["bar"] = 2;
aa["batz"] = 3;
assert(aa.keys.length == 4);
assert(aa.values.length == 4);
foreach (a; aa.keys)
{
assert(a.length != 0);
assert(a.ptr != null);
}
foreach (v; aa.values)
{
assert(v != 0);
}
}
void testGet1() @safe
{
int[string] aa;
int a;
foreach (val; aa.byKeyValue)
{
++aa[val.key];
a = val.value;
}
}
void testGet2()
{
static class T
{
static size_t count;
this() { ++count; }
}
T[string] aa;
auto a = new T;
aa["foo"] = a;
assert(T.count == 1);
auto b = aa.get("foo", new T);
assert(T.count == 1);
assert(b is a);
auto c = aa.get("bar", new T);
assert(T.count == 2);
assert(c !is a);
//Obviously get doesn't add.
assert("bar" !in aa);
}
void testRequire1()
{
static class T
{
static size_t count;
this() { ++count; }
}
T[string] aa;
auto a = new T;
aa["foo"] = a;
assert(T.count == 1);
auto b = aa.require("foo", new T);
assert(T.count == 1);
assert(b is a);
auto c = aa.require("bar", null);
assert(T.count == 1);
assert(c is null);
assert("bar" in aa);
auto d = aa.require("bar", new T);
assert(d is null);
auto e = aa.require("baz", new T);
assert(T.count == 2);
assert(e !is a);
assert("baz" in aa);
bool created = false;
auto f = aa.require("qux", { created = true; return new T; }());
assert(created == true);
T g;
auto h = aa.require("qux", { g = new T; return g; }());
assert(g !is h);
}
void testRequire2()
{
static struct S
{
int value;
}
S[string] aa;
aa.require("foo").value = 1;
assert(aa == ["foo" : S(1)]);
aa["bar"] = S(2);
auto a = aa.require("bar", S(3));
assert(a == S(2));
auto b = aa["bar"];
assert(b == S(2));
S* c = &aa.require("baz", S(4));
assert(c is &aa["baz"]);
assert(*c == S(4));
assert("baz" in aa);
auto d = aa["baz"];
assert(d == S(4));
}
void testRequire3() pure
{
string[string] aa;
auto a = aa.require("foo", "bar");
assert("foo" in aa);
}
void testUpdate1()
{
static class C {}
C[string] aa;
C orig = new C;
aa["foo"] = orig;
C newer;
C older;
void test(string key)
{
aa.update(key, {
newer = new C;
return newer;
}, (ref C c) {
older = c;
newer = new C;
return newer;
});
}
test("foo");
assert(older is orig);
assert(newer is aa["foo"]);
test("bar");
assert(newer is aa["bar"]);
}
void testUpdate2()
{
static class C {}
C[string] aa;
auto created = false;
auto updated = false;
class Creator
{
C opCall()
{
created = true;
return new C();
}
}
class Updater
{
C opCall(ref C)
{
updated = true;
return new C();
}
}
aa.update("foo", new Creator, new Updater);
assert(created);
aa.update("foo", new Creator, new Updater);
assert(updated);
}
void testByKey1()
{
static assert(!__traits(compiles,
() @safe {
struct BadValue
{
int x;
this(this) @safe { *(cast(ubyte*)(null) + 100000) = 5; } // not @safe
alias x this;
}
BadValue[int] aa;
() @safe { auto x = aa.byKey.front; } ();
}
));
}
void testByKey2() nothrow pure
{
int[int] a;
foreach (i; a.byKey)
{
assert(false);
}
foreach (i; a.byValue)
{
assert(false);
}
}
void testByKey3() /*nothrow*/ pure
{
auto a = [ 1:"one", 2:"two", 3:"three" ];
auto b = a.dup;
assert(b == [ 1:"one", 2:"two", 3:"three" ]);
int[] c;
foreach (k; a.byKey)
{
c ~= k;
}
assert(c.length == 3);
assert(c[0] == 1 || c[1] == 1 || c[2] == 1);
assert(c[0] == 2 || c[1] == 2 || c[2] == 2);
assert(c[0] == 3 || c[1] == 3 || c[2] == 3);
}
void testByKey4() nothrow pure
{
string[] keys = ["a", "b", "c", "d", "e", "f"];
// Test forward range capabilities of byKey
{
int[string] aa;
foreach (key; keys)
aa[key] = 0;
auto keyRange = aa.byKey();
auto savedKeyRange = keyRange.save;
// Consume key range once
size_t keyCount = 0;
while (!keyRange.empty)
{
aa[keyRange.front]++;
keyCount++;
keyRange.popFront();
}
foreach (key; keys)
{
assert(aa[key] == 1);
}
assert(keyCount == keys.length);
// Verify it's possible to iterate the range the second time
keyCount = 0;
while (!savedKeyRange.empty)
{
aa[savedKeyRange.front]++;
keyCount++;
savedKeyRange.popFront();
}
foreach (key; keys)
{
assert(aa[key] == 2);
}
assert(keyCount == keys.length);
}
// Test forward range capabilities of byValue
{
size_t[string] aa;
foreach (i; 0 .. keys.length)
{
aa[keys[i]] = i;
}
auto valRange = aa.byValue();
auto savedValRange = valRange.save;
// Consume value range once
int[] hasSeen;
hasSeen.length = keys.length;
while (!valRange.empty)
{
assert(hasSeen[valRange.front] == 0);
hasSeen[valRange.front]++;
valRange.popFront();
}
foreach (sawValue; hasSeen) { assert(sawValue == 1); }
// Verify it's possible to iterate the range the second time
hasSeen = null;
hasSeen.length = keys.length;
while (!savedValRange.empty)
{
assert(!hasSeen[savedValRange.front]);
hasSeen[savedValRange.front] = true;
savedValRange.popFront();
}
foreach (sawValue; hasSeen) { assert(sawValue); }
}
}
void issue5842() pure nothrow
{
string[string] test = null;
test["test1"] = "test1";
test.remove("test1");
test.rehash;
test["test3"] = "test3"; // causes divide by zero if rehash broke the AA
}
/// expanded test for 5842: increase AA size past the point where the AA
/// stops using binit, in order to test another code path in rehash.
void issue5842Expanded() pure nothrow
{
int[int] aa;
foreach (int i; 0 .. 32)
aa[i] = i;
foreach (int i; 0 .. 32)
aa.remove(i);
aa.rehash;
aa[1] = 1;
}
void issue5925() nothrow pure
{
const a = [4:0];
const b = [4:0];
assert(a == b);
}
/// test for bug 8583: ensure Slot and aaA are on the same page wrt value alignment
void issue8583() nothrow pure
{
string[byte] aa0 = [0: "zero"];
string[uint[3]] aa1 = [[1,2,3]: "onetwothree"];
ushort[uint[3]] aa2 = [[9,8,7]: 987];
ushort[uint[4]] aa3 = [[1,2,3,4]: 1234];
string[uint[5]] aa4 = [[1,2,3,4,5]: "onetwothreefourfive"];
assert(aa0.byValue.front == "zero");
assert(aa1.byValue.front == "onetwothree");
assert(aa2.byValue.front == 987);
assert(aa3.byValue.front == 1234);
assert(aa4.byValue.front == "onetwothreefourfive");
}
void issue9052() nothrow pure
{
static struct Json {
Json[string] aa;
void opAssign(Json) {}
size_t length() const { return aa.length; }
// This length() instantiates AssociativeArray!(string, const(Json)) to call AA.length(), and
// inside ref Slot opAssign(Slot p); (which is automatically generated by compiler in Slot),
// this.value = p.value would actually fail, because both side types of the assignment
// are const(Json).
}
}
void issue9119()
{
int[string] aa;
assert(aa.byKeyValue.empty);
aa["a"] = 1;
aa["b"] = 2;
aa["c"] = 3;
auto pairs = aa.byKeyValue;
auto savedPairs = pairs.save;
size_t count = 0;
while (!pairs.empty)
{
assert(pairs.front.key in aa);
assert(pairs.front.value == aa[pairs.front.key]);
count++;
pairs.popFront();
}
assert(count == aa.length);
// Verify that saved range can iterate over the AA again
count = 0;
while (!savedPairs.empty)
{
assert(savedPairs.front.key in aa);
assert(savedPairs.front.value == aa[savedPairs.front.key]);
count++;
savedPairs.popFront();
}
assert(count == aa.length);
}
void issue9852() nothrow pure
{
// Original test case (revised, original assert was wrong)
int[string] a;
a["foo"] = 0;
a.remove("foo");
assert(a == null); // should not crash
int[string] b;
assert(b is null);
assert(a == b); // should not deref null
assert(b == a); // ditto
int[string] c;
c["a"] = 1;
assert(a != c); // comparison with empty non-null AA
assert(c != a);
assert(b != c); // comparison with null AA
assert(c != b);
}
void issue10381()
{
alias II = int[int];
II aa1 = [0 : 1];
II aa2 = [0 : 1];
II aa3 = [0 : 2];
assert(aa1 == aa2); // Passes
assert(typeid(II).equals(&aa1, &aa2));
assert(!typeid(II).equals(&aa1, &aa3));
}
void issue10720() nothrow pure
{
static struct NC
{
@disable this(this) { }
}
NC[string] aa;
static assert(!is(aa.nonExistingField));
}
/// bug 11761: test forward range functionality
void issue11761() pure nothrow
{
auto aa = ["a": 1];
void testFwdRange(R, T)(R fwdRange, T testValue)
{
assert(!fwdRange.empty);
assert(fwdRange.front == testValue);
static assert(is(typeof(fwdRange.save) == typeof(fwdRange)));
auto saved = fwdRange.save;
fwdRange.popFront();
assert(fwdRange.empty);
assert(!saved.empty);
assert(saved.front == testValue);
saved.popFront();
assert(saved.empty);
}
testFwdRange(aa.byKey, "a");
testFwdRange(aa.byValue, 1);
//testFwdRange(aa.byPair, tuple("a", 1));
}
void issue13078() nothrow pure
{
shared string[][string] map;
map.rehash;
}
void issue14104()
{
import core.stdc.stdio;
alias K = const(ubyte)*;
size_t[K] aa;
immutable key = cast(K)(cast(size_t) uint.max + 1);
aa[key] = 12;
assert(key in aa);
}
void issue14626()
{
static struct S
{
string[string] aa;
inout(string) key() inout { return aa.byKey().front; }
inout(string) val() inout { return aa.byValue().front; }
auto keyval() inout { return aa.byKeyValue().front; }
}
S s = S(["a":"b"]);
assert(s.key() == "a");
assert(s.val() == "b");
assert(s.keyval().key == "a");
assert(s.keyval().value == "b");
void testInoutKeyVal(inout(string) key)
{
inout(string)[typeof(key)] aa;
foreach (i; aa.byKey()) {}
foreach (i; aa.byValue()) {}
foreach (i; aa.byKeyValue()) {}
}
const int[int] caa;
static assert(is(typeof(caa.byValue().front) == const int));
}
/// test duplicated keys in AA literal
/// https://issues.dlang.org/show_bug.cgi?id=15290
void issue15290()
{
string[int] aa = [ 0: "a", 0: "b" ];
assert(aa.length == 1);
assert(aa.keys == [ 0 ]);
}
void issue15367()
{
void f1() {}
void f2() {}
// TypeInfo_Delegate.getHash
int[void delegate()] aa;
assert(aa.length == 0);
aa[&f1] = 1;
assert(aa.length == 1);
aa[&f1] = 1;
assert(aa.length == 1);
auto a1 = [&f2, &f1];
auto a2 = [&f2, &f1];
// TypeInfo_Delegate.equals
for (auto i = 0; i < 2; i++)
assert(a1[i] == a2[i]);
assert(a1 == a2);
// TypeInfo_Delegate.compare
for (auto i = 0; i < 2; i++)
assert(a1[i] <= a2[i]);
assert(a1 <= a2);
}
/// test AA as key
/// https://issues.dlang.org/show_bug.cgi?id=16974
void issue16974()
{
int[int] a = [1 : 2], a2 = [1 : 2];
assert([a : 3] == [a : 3]);
assert([a : 3] == [a2 : 3]);
assert(typeid(a).getHash(&a) == typeid(a).getHash(&a));
assert(typeid(a).getHash(&a) == typeid(a).getHash(&a2));
}
/// test safety for alias-this'd AA that have unsafe opCast
/// https://issues.dlang.org/show_bug.cgi?id=18071
void issue18071()
{
static struct Foo
{
int[int] aa;
auto opCast() pure nothrow @nogc
{
*cast(uint*)0xdeadbeef = 0xcafebabe;// unsafe
return null;
}
alias aa this;
}
Foo f;
() @safe { assert(f.byKey.empty); }();
}
/// Verify iteration with const.
void testIterationWithConst()
{
auto aa = [1:2, 3:4];
foreach (const t; aa.byKeyValue)
{
auto k = t.key;
auto v = t.value;
}
}
void testStructArrayKey() @safe
{
struct S
{
int i;
const @safe nothrow:
hash_t toHash() { return 0; }
bool opEquals(const S) { return true; }
int opCmp(const S) { return 0; }
}
int[S[]] aa = [[S(11)] : 13];
assert(aa[[S(12)]] == 13);
}
void miscTests1() pure nothrow
{
string[int] key1 = [1 : "true", 2 : "false"];
string[int] key2 = [1 : "false", 2 : "true"];
string[int] key3;
// AA lits create a larger hashtable
int[string[int]] aa1 = [key1 : 100, key2 : 200, key3 : 300];
// Ensure consistent hash values are computed for key1
assert((key1 in aa1) !is null);
// Manually assigning to an empty AA creates a smaller hashtable
int[string[int]] aa2;
aa2[key1] = 100;
aa2[key2] = 200;
aa2[key3] = 300;
assert(aa1 == aa2);
// Ensure binary-independence of equal hash keys
string[int] key2a;
key2a[1] = "false";
key2a[2] = "true";
assert(aa1[key2a] == 200);
}
void miscTests2()
{
int[int] aa;
foreach (k, v; aa)
assert(false);
foreach (v; aa)
assert(false);
assert(aa.byKey.empty);
assert(aa.byValue.empty);
assert(aa.byKeyValue.empty);
size_t n;
aa = [0 : 3, 1 : 4, 2 : 5];
foreach (k, v; aa)
{
n += k;
assert(k >= 0 && k < 3);
assert(v >= 3 && v < 6);
}
assert(n == 3);
n = 0;
foreach (v; aa)
{
n += v;
assert(v >= 3 && v < 6);
}
assert(n == 12);
n = 0;
foreach (k, v; aa)
{
++n;
break;
}
assert(n == 1);
n = 0;
foreach (v; aa)
{
++n;
break;
}
assert(n == 1);
}
void testRemove()
{
int[int] aa;
assert(!aa.remove(0));
aa = [0 : 1];
assert(aa.remove(0));
assert(!aa.remove(0));
aa[1] = 2;
assert(!aa.remove(0));
assert(aa.remove(1));
assert(aa.length == 0);
assert(aa.byKey.empty);
}
/// test zero sized value (hashset)
void testZeroSizedValue()
{
alias V = void[0];
auto aa = [0 : V.init];
assert(aa.length == 1);
assert(aa.byKey.front == 0);
assert(aa.byValue.front == V.init);
aa[1] = V.init;
assert(aa.length == 2);
aa[0] = V.init;
assert(aa.length == 2);
assert(aa.remove(0));
aa[0] = V.init;
assert(aa.length == 2);
assert(aa == [0 : V.init, 1 : V.init]);
}
void testTombstonePurging()
{
int[int] aa;
foreach (i; 0 .. 6)
aa[i] = i;
foreach (i; 0 .. 6)
assert(aa.remove(i));
foreach (i; 6 .. 10)
aa[i] = i;
assert(aa.length == 4);
foreach (i; 6 .. 10)
assert(i in aa);
}
void testClear()
{
int[int] aa;
assert(aa.length == 0);
foreach (i; 0 .. 100)
aa[i] = i * 2;
assert(aa.length == 100);
auto aa2 = aa;
assert(aa2.length == 100);
aa.clear();
assert(aa.length == 0);
assert(aa2.length == 0);
aa2[5] = 6;
assert(aa.length == 1);
assert(aa[5] == 6);
}

View File

@ -0,0 +1,29 @@
# Copyright (C) 2018 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
load_lib libphobos-dg.exp
# Initialize dg.
dg-init
# Gather a list of all tests.
set tests [lsort [find $srcdir/$subdir *.d]]
# Main loop.
dg-runtest $tests "" $DEFAULT_DFLAGS
# All done.
dg-finish

View File

@ -0,0 +1,540 @@
void main()
{
issue19562();
issue15111();
issues16654And16764();
issue18918();
issue18925();
issue19005();
issue19204();
issue19262();
issue19568();
issue19582();
testTypeInfoArrayGetHash1();
testTypeInfoArrayGetHash2();
pr2243();
}
/// Check hashOf an array of void pointers or delegates is @safe.
void issue19562() @nogc nothrow pure @safe
{
void*[10] val;
size_t h = hashOf(val[]);
alias D = void delegate();
D[10] ds;
h = hashOf(ds[]);
}
/// hashOf was failing for structs that had an `alias this` to a dynamic array.
void issue15111()
{
void testAlias(T)()
{
static struct Foo
{
T t;
alias t this;
}
Foo foo;
static assert(is(typeof(hashOf(foo))));
}
// was fixed
testAlias!(int[]);
testAlias!(int*);
// was not affected
testAlias!int;
testAlias!(void delegate());
testAlias!(string[string]);
testAlias!(int[8]);
}
void issues16654And16764()
{
auto a = [1];
auto b = a.dup;
assert(hashOf(a) == hashOf(b));
}
/// Check hashOf dynamic array of scalars is usable in @safe code.
void issue18918() nothrow pure @safe
{
const _ = (() @nogc => hashOf("abc"))();
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);
}
/// Check hashOf struct of scalar fields is usable in @safe code.
void issue18925() @nogc nothrow pure @safe
{
static struct S { int a; int b; }
auto h = hashOf(S.init);
}
void issue19005() @nogc nothrow pure @safe
{
enum Month : ubyte
{
jan = 1
}
static struct Date
{
short _year;
Month _month;
ubyte _day;
}
Date date;
auto hash = date.hashOf;
}
/// Accept SIMD vectors.
void issue19204() @nogc nothrow pure @safe
{
version (D_SIMD)
{
static import simd = core.simd;
static if (is(simd.int4)) // __traits(isArithmetic)
{{
enum simd.int4 val = [1,2,3,4];
enum ctfeHash = hashOf(val);
simd.int4 rtVal = val;
auto rtHash = hashOf(rtVal);
assert(ctfeHash == rtHash);
}}
static if (is(simd.void16)) // non __traits(isArithmetic)
{{
auto h = hashOf(simd.void16.init);
}}
static if (is(simd.float4)) // __traits(isArithmetic) and __traits(isFloating)
{{
enum simd.float4 val = [1.1f, 2.2f, 3.3f, 4.4f];
enum ctfeHash = hashOf(val);
simd.float4 rtVal = val;
auto rtHash = hashOf(rtVal);
assert(ctfeHash == rtHash);
}}
}
}
/// hashOf associative array should infer nothrow
void issue19262() nothrow
{
int[int] aa;
auto h = hashOf(aa);
h = hashOf(aa, h);
}
/// hashOf should not unnecessarily call a struct's fields' postblits & dtors in CTFE
void issue19568()
{
static struct S1
{
@disable this(this);
~this() @nogc nothrow
{
import core.stdc.stdio;
if (mptr) puts("impure");
}
size_t[2] pad;
void* mptr;
}
static struct S2
{
@disable this(this);
~this() @nogc nothrow
{
import core.stdc.stdio;
if (fd != -1) puts("impure");
}
int fd = -1;
S1 s1;
}
static struct S3
{
private S2 s2;
}
S3 s3;
size_t h = ((ref S3 s3) pure => hashOf(s3))(s3);
}
/// Check core.internal.convert.toUbyte in CTFE for arrays works with
/// reference type elements and doesn't call postblits/dtors.
void issue19582()
{
import core.internal.convert : toUbyte;
final static class C : Object {}
enum b1 = (() @nogc nothrow pure @safe { C[10] o; return toUbyte(o[])[0]; })();
static struct S
{
int x;
@disable this(this);
~this() @nogc nothrow
{
import core.stdc.stdio : puts;
if (x) puts("impure");
}
}
enum b2 = () {
S[10] a;
return ((const S[] a) @nogc nothrow pure @safe => toUbyte(a))(a);
}();
}
/// Tests ensure TypeInfo_Array.getHash uses element hash functions instead
/// of hashing array data.
void testTypeInfoArrayGetHash1()
{
class C
{
int i;
this(in int i) { this.i = i; }
override hash_t toHash() { return 0; }
}
C[] a1 = [new C(11)], a2 = [new C(12)];
assert(typeid(C[]).getHash(&a1) == typeid(C[]).getHash(&a2));
}
/// ditto
void testTypeInfoArrayGetHash2()
{
struct S
{
int i;
hash_t toHash() const @safe nothrow { return 0; }
}
S[] a1 = [S(11)], a2 = [S(12)];
assert(typeid(S[]).getHash(&a1) == typeid(S[]).getHash(&a2));
}
/++
Use the new `core.internal.hash.hashOf` in all `TypeInfo.getHash` instead of
the `old rt.util.hash.hashOf`. Also make `typeid(T).getHash(&val)` get the
same result as `hashOf(val)`.
+/
void pr2243()
{
static struct Foo
{
int a = 99;
float b = 4.0;
size_t toHash() const pure @safe nothrow
{
return a;
}
}
static struct Bar
{
char c = 'x';
int a = 99;
float b = 4.0;
void* d = null;
}
static struct Boom
{
char c = 'M';
int* a = null;
}
static struct Plain
{
int a = 1;
int b = 2;
}
interface IBoo
{
void boo();
}
static class Boo: IBoo
{
override void boo()
{
}
override size_t toHash()
{
return 1;
}
}
static struct Goo
{
size_t toHash() pure @safe nothrow
{
return 1;
}
}
enum Gun: long
{
A = 99,
B = 17
}
enum double dexpr = 3.14;
enum float fexpr = 2.71;
enum wstring wsexpr = "abcdef"w;
enum string csexpr = "abcdef";
enum int iexpr = 7;
enum long lexpr = 42;
enum int[2][3] saexpr = [[1, 2], [3, 4], [5, 6]];
enum int[] daexpr = [7,8,9];
enum Foo thsexpr = Foo();
enum Bar vsexpr = Bar();
enum int[int] aaexpr = [99:2, 12:6, 45:4];
enum Gun eexpr = Gun.A;
enum cdouble cexpr = 7+4i;
enum Foo[] staexpr = [Foo(), Foo(), Foo()];
enum Bar[] vsaexpr = [Bar(), Bar(), Bar()];
enum realexpr = 7.88;
enum raexpr = [8.99L+86i, 3.12L+99i, 5.66L+12i];
enum nullexpr = null;
enum plstr = Plain();
enum plarrstr = [Plain(), Plain(), Plain()];
//No CTFE:
Boom rstructexpr = Boom();
Boom[] rstrarrexpr = [Boom(), Boom(), Boom()];
int delegate() dgexpr = (){return 78;};
void* ptrexpr = &dgexpr;
//CTFE hashes
enum h1 = dexpr.hashOf();
enum h2 = fexpr.hashOf();
enum h3 = wsexpr.hashOf();
enum h4 = csexpr.hashOf();
enum h5 = iexpr.hashOf();
enum h6 = lexpr.hashOf();
enum h7 = saexpr.hashOf();
enum h8 = daexpr.hashOf();
enum h9 = thsexpr.hashOf();
enum h10 = vsexpr.hashOf();
enum h11 = aaexpr.hashOf();
enum h12 = eexpr.hashOf();
enum h13 = cexpr.hashOf();
enum h14 = hashOf(new Boo);
enum h15 = staexpr.hashOf();
enum h16 = hashOf([new Boo, new Boo, new Boo]);
enum h17 = hashOf([cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]);
enum h18 = hashOf(cast(IBoo)new Boo);
enum h19 = vsaexpr.hashOf();
enum h20 = hashOf(cast(Foo[3])staexpr);
//BUG: cannot cast [Boo(), Boo(), Boo()][0] to object.Object at compile time
auto h21 = hashOf(cast(Boo[3])[new Boo, new Boo, new Boo]);
auto h22 = hashOf(cast(IBoo[3])[cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo]);
enum h23 = hashOf(cast(Bar[3])vsaexpr);
//NO CTFE (Compute, but don't check correctness):
auto h24 = rstructexpr.hashOf();
auto h25 = rstrarrexpr.hashOf();
auto h26 = dgexpr.hashOf();
auto h27 = ptrexpr.hashOf();
enum h28 = realexpr.hashOf();
enum h29 = raexpr.hashOf();
enum h30 = nullexpr.hashOf();
enum h31 = plstr.hashOf();
enum h32 = plarrstr.hashOf();
enum h33 = hashOf(cast(Plain[3])plarrstr);
auto v1 = dexpr;
auto v2 = fexpr;
auto v3 = wsexpr;
auto v4 = csexpr;
auto v5 = iexpr;
auto v6 = lexpr;
auto v7 = saexpr;
auto v8 = daexpr;
auto v9 = thsexpr;
auto v10 = vsexpr;
auto v11 = aaexpr;
auto v12 = eexpr;
auto v13 = cexpr;
auto v14 = new Boo;
auto v15 = staexpr;
auto v16 = [new Boo, new Boo, new Boo];
auto v17 = [cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo];
auto v18 = cast(IBoo)new Boo;
auto v19 = vsaexpr;
auto v20 = cast(Foo[3])staexpr;
auto v21 = cast(Boo[3])[new Boo, new Boo, new Boo];
auto v22 = cast(IBoo[3])[cast(IBoo)new Boo, cast(IBoo)new Boo, cast(IBoo)new Boo];
auto v23 = cast(Bar[3])vsaexpr;
auto v30 = null;
auto v31 = plstr;
auto v32 = plarrstr;
auto v33 = cast(Plain[3])plarrstr;
//NO CTFE:
auto v24 = rstructexpr;
auto v25 = rstrarrexpr;
auto v26 = dgexpr;
auto v27 = ptrexpr;
auto v28 = realexpr;
auto v29 = raexpr;
//runtime hashes
auto rth1 = hashOf(v1);
auto rth2 = hashOf(v2);
auto rth3 = hashOf(v3);
auto rth4 = hashOf(v4);
auto rth5 = hashOf(v5);
auto rth6 = hashOf(v6);
auto rth7 = hashOf(v7);
auto rth8 = hashOf(v8);
auto rth9 = hashOf(v9);
auto rth10 = hashOf(v10);
auto rth11 = hashOf(v11);
auto rth12 = hashOf(v12);
auto rth13 = hashOf(v13);
auto rth14 = hashOf(v14);
auto rth15 = hashOf(v15);
auto rth16 = hashOf(v16);
auto rth17 = hashOf(v17);
auto rth18 = hashOf(v18);
auto rth19 = hashOf(v19);
auto rth20 = hashOf(v20);
auto rth21 = hashOf(v21);
auto rth22 = hashOf(v22);
auto rth23 = hashOf(v23);
auto rth30 = hashOf(v30);
//NO CTFE:
auto rth24 = hashOf(v24);
auto rth25 = hashOf(v25);
auto rth26 = hashOf(v26);
auto rth27 = hashOf(v27);
auto rth28 = hashOf(v28);
auto rth29 = hashOf(v29);
auto rth31 = hashOf(v31);
auto rth32 = hashOf(v32);
auto rth33 = hashOf(v33);
assert(h1 == rth1);
assert(h2 == rth2);
assert(h3 == rth3);
assert(h4 == rth4);
assert(h5 == rth5);
assert(h6 == rth6);
assert(h7 == rth7);
assert(h8 == rth8);
assert(h9 == rth9);
assert(h10 == rth10);
assert(h11 == rth11);
assert(h12 == rth12);
assert(h13 == rth13);
assert(h14 == rth14);
assert(h15 == rth15);
assert(h16 == rth16);
assert(h17 == rth17);
assert(h18 == rth18);
assert(h19 == rth19);
assert(h20 == rth20);
assert(h21 == rth21);
assert(h22 == rth22);
assert(h23 == rth23);
/*assert(h24 == rth24);
assert(h25 == rth25);
assert(h26 == rth26);
assert(h27 == rth27);
assert(h28 == rth28);
assert(h29 == rth29);*/
assert(h30 == rth30);
assert(h31 == rth31);
assert(h32 == rth32);
assert(h33 == rth33);
// https://issues.dlang.org/show_bug.cgi?id=18932
assert(hashOf(null, 0) != hashOf(null, 123456789));
static size_t tiHashOf(T)(T var)
{
return typeid(T).getHash(&var);
}
auto tih1 = tiHashOf(v1);
auto tih2 = tiHashOf(v2);
auto tih3 = tiHashOf(v3);
auto tih4 = tiHashOf(v4);
auto tih5 = tiHashOf(v5);
auto tih6 = tiHashOf(v6);
auto tih7 = tiHashOf(v7);
auto tih8 = tiHashOf(v8);
auto tih9 = tiHashOf(v9);
auto tih10 = tiHashOf(v10);
auto tih11 = tiHashOf(v11);
auto tih12 = tiHashOf(v12);
auto tih13 = tiHashOf(v13);
auto tih14 = tiHashOf(v14);
auto tih15 = tiHashOf(v15);
auto tih16 = tiHashOf(v16);
auto tih17 = tiHashOf(v17);
auto tih18 = tiHashOf(v18);
auto tih19 = tiHashOf(v19);
auto tih20 = tiHashOf(v20);
auto tih21 = tiHashOf(v21);
auto tih22 = tiHashOf(v22);
auto tih23 = tiHashOf(v23);
auto tih24 = tiHashOf(v24);
auto tih25 = tiHashOf(v25);
auto tih26 = tiHashOf(v26);
auto tih27 = tiHashOf(v27);
auto tih28 = tiHashOf(v28);
auto tih29 = tiHashOf(v29);
auto tih30 = tiHashOf(v30);
auto tih31 = tiHashOf(v31);
auto tih32 = tiHashOf(v32);
auto tih33 = tiHashOf(v33);
assert(tih1 == rth1);
assert(tih2 == rth2);
assert(tih3 == rth3);
assert(tih4 == rth4);
assert(tih5 == rth5);
assert(tih6 == rth6);
assert(tih7 == rth7);
assert(tih8 == rth8);
assert(tih9 == rth9);
//assert(tih10 == rth10); // need compiler-generated __xtoHash changes
assert(tih11 == rth11);
assert(tih12 == rth12);
assert(tih13 == rth13);
assert(tih14 == rth14);
assert(tih15 == rth15);
assert(tih16 == rth16);
assert(tih17 == rth17);
assert(tih18 == rth18);
//assert(tih19 == rth19); // need compiler-generated __xtoHash changes
assert(tih20 == rth20);
assert(tih21 == rth21);
assert(tih22 == rth22);
//assert(tih23 == rth23); // need compiler-generated __xtoHash changes
//assert(tih24 == rth24);
//assert(tih25 == rth25);
assert(tih26 == rth26);
assert(tih27 == rth27);
assert(tih28 == rth28);
//assert(tih29 == rth29); // XGDC: Implementation wrongly hashes padding.
assert(tih30 == rth30);
assert(tih31 == rth31);
assert(tih32 == rth32);
assert(tih33 == rth33);
}