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

Commit

Permalink
Merge pull request #2228 from n8sh/hash-nogc
Browse files Browse the repository at this point in the history
Fix Issue 19009 - core.internal.hash.hashOf default hash (absent `toHash`) should be `@nogc`
merged-on-behalf-of: Steven Schveighoffer <schveiguy@users.noreply.github.com>
  • Loading branch information
dlang-bot committed Jun 21, 2018
2 parents 0c92d13 + 4f5b049 commit 753239f
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 32 deletions.
86 changes: 59 additions & 27 deletions src/core/internal/convert.d
Expand Up @@ -10,13 +10,36 @@
module core.internal.convert;
import core.internal.traits : Unqual;

@trusted pure nothrow
/+
A @nogc function can allocate memory during CTFE.
+/
@nogc nothrow pure @trusted
private ubyte[] ctfe_alloc()(size_t n)
{
if (!__ctfe)
{
assert(0, "CTFE only");
}
else
{
static ubyte[] alloc(size_t x) nothrow pure
{
if (__ctfe) // Needed to prevent _d_newarray from appearing in compiled prorgam.
return new ubyte[x];
else
assert(0);
}
return (cast(ubyte[] function(size_t) @nogc nothrow pure) &alloc)(n);
}
}

@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(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))
{
static const(ubyte)[] reverse_(const(ubyte)[] arr)
{
ubyte[] buff = new ubyte[arr.length];
ubyte[] buff = ctfe_alloc(arr.length);
foreach(k, v; arr)
{
buff[$-k-1] = v;
Expand All @@ -31,7 +54,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T ==
uint exp = parsed.exponent;
uint sign = parsed.sign;

ubyte[T.sizeof] buff;
ubyte[] buff = ctfe_alloc(T.sizeof);
size_t off_bytes = 0;
size_t off_bits = 0;

Expand Down Expand Up @@ -60,7 +83,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T ==

version(LittleEndian)
{
return buff.dup;
return buff;
}
else
{
Expand All @@ -73,13 +96,13 @@ const(ubyte)[] toUbyte(T)(ref T val) if(is(Unqual!T == float) || is(Unqual!T ==
}
}

@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_;
Expand Down Expand Up @@ -116,7 +139,7 @@ private Float parse(bool is_denormalized = false, T:real)(T x_) if(floatFormat!T
return Float(mant, exp, sign);
}

@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_;
Expand Down Expand Up @@ -228,10 +251,10 @@ private template FloatTraits(T) if(floatFormat!T == FloatFormat.Quadruple) //Uns
}


@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);

Expand All @@ -256,13 +279,13 @@ 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
@safe pure nothrow @nogc
private uint binLog2(T)(T x)
{
assert(x > 0);
Expand Down Expand Up @@ -290,7 +313,7 @@ private uint binLog2(T)(T x)
return max;
}

@safe pure nothrow
@safe pure nothrow @nogc
private ulong denormalizedMantissa(T)(T x) if(floatFormat!T == FloatFormat.Real80)
{
x *= 2.0L^^FloatTraits!T.MANTISSA;
Expand All @@ -299,7 +322,7 @@ private ulong denormalizedMantissa(T)(T x) if(floatFormat!T == FloatFormat.Real8
return fl.mantissa >> pow;
}

@safe pure nothrow
@safe pure nothrow @nogc
private ulong denormalizedMantissa(T)(T x) if(floatFormat!T != FloatFormat.Real80)
{
x *= 2.0L^^FloatTraits!T.MANTISSA;
Expand Down Expand Up @@ -475,21 +498,23 @@ template floatFormat(T) if(is(T:real) || is(T:ireal))
}

// all toUbyte functions must be evaluable at compile time
@trusted pure nothrow
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(T[] arr) if (T.sizeof == 1)
{
return cast(const(ubyte)[])arr;
}

@trusted pure nothrow
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyte)[])) && (T.sizeof > 1))
{
if (__ctfe)
{
const(ubyte)[] ret;
ubyte[] ret = ctfe_alloc(T.sizeof * arr.length);
size_t offset = 0;
foreach (cur; arr)
{
ret ~= toUbyte(cur);
ret[offset .. offset + T.sizeof] = toUbyte(cur)[0 .. T.sizeof];
offset += T.sizeof;
}
return ret;
}
Expand All @@ -499,14 +524,16 @@ const(ubyte)[] toUbyte(T)(T[] arr) if ((is(typeof(toUbyte(arr[0])) == const(ubyt
}
}

@trusted pure nothrow
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(ref T val) if (__traits(isIntegral, T) && !is(T == enum))
{
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
{
Expand All @@ -515,7 +542,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)
{
Expand All @@ -525,30 +552,35 @@ 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
{
return (cast(const(ubyte)*)(&val))[0 .. T.sizeof];
}
}

@trusted pure nothrow
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(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
{
return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
}
}

@trusted pure nothrow
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(ref T val) if (is(T == enum) && is(typeof(toUbyte(cast(V)val)) == const(ubyte)[]))
{
if (__ctfe)
Expand Down Expand Up @@ -605,12 +637,12 @@ private bool isNonReferenceStruct(T)() if (is(T == struct) || is(T == union))
return true;
}

@trusted pure nothrow
@trusted pure nothrow @nogc
const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union))
{
if (__ctfe)
{
ubyte[T.sizeof] bytes;
ubyte[] bytes = ctfe_alloc(T.sizeof);
foreach (key, cur; val.tupleof)
{
alias CUR_TYPE = typeof(cur);
Expand All @@ -629,7 +661,7 @@ const(ubyte)[] toUbyte(T)(ref T val) if (is(T == struct) || is(T == union))
assert(0, "Unable to compute byte representation of "~typeof(CUR_TYPE).stringof~" field at compile time");
}
}
return bytes[].dup;
return bytes;
}
else
{
Expand Down
10 changes: 5 additions & 5 deletions src/core/internal/hash.d
Expand Up @@ -72,14 +72,14 @@ if (!is(T == enum) && !is(T : typeof(null)) && is(T S: S[]) && !__traits(isStati
const _ = hashOf("abc");
}

nothrow pure @system unittest
@nogc nothrow pure @system unittest
{
void*[] val;
const _ = hashOf(val); // Check a PR doesn't break this.
}

//arithmetic type hash
@trusted nothrow pure
@trusted @nogc nothrow pure
size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && __traits(isArithmetic, T))
{
static if(__traits(isFloating, val))
Expand All @@ -94,14 +94,14 @@ size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && __traits
}

//typeof(null) hash. CTFE supported
@trusted nothrow pure
@trusted @nogc nothrow pure
size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T : typeof(null)))
{
return hashOf(cast(void*)null, seed);
}

//Pointers hash. CTFE unsupported if not null
@trusted nothrow pure
@trusted @nogc nothrow pure
size_t hashOf(T)(auto ref T val, size_t seed = 0)
if (!is(T == enum) && is(T V : V*) && !is(T : typeof(null))
&& !is(T == struct) && !is(T == class) && !is(T == union))
Expand Down Expand Up @@ -155,7 +155,7 @@ nothrow pure @safe unittest // issue 18925
}

//delegate hash. CTFE unsupported
@trusted nothrow pure
@trusted @nogc nothrow pure
size_t hashOf(T)(auto ref T val, size_t seed = 0) if (!is(T == enum) && is(T == delegate))
{
assert(!__ctfe, "unable to compute hash of "~T.stringof);
Expand Down

0 comments on commit 753239f

Please sign in to comment.