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:
parent
f1b7b50aff
commit
e613d99266
50 changed files with 2647 additions and 1385 deletions
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
||||
|
|
29
libphobos/testsuite/libphobos.aa/aa.exp
Normal file
29
libphobos/testsuite/libphobos.aa/aa.exp
Normal 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
|
856
libphobos/testsuite/libphobos.aa/test_aa.d
Normal file
856
libphobos/testsuite/libphobos.aa/test_aa.d
Normal 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);
|
||||
}
|
29
libphobos/testsuite/libphobos.hash/hash.exp
Normal file
29
libphobos/testsuite/libphobos.hash/hash.exp
Normal 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
|
540
libphobos/testsuite/libphobos.hash/test_hash.d
Normal file
540
libphobos/testsuite/libphobos.hash/test_hash.d
Normal 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);
|
||||
}
|
Loading…
Add table
Reference in a new issue