Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,6 @@ SRCS=\
src\rt\backtrace\elf.d \
\
src\rt\util\array.d \
src\rt\util\hash.d \
src\rt\util\random.d \
src\rt\util\typeinfo.d \
src\rt\util\utf.d \
Expand Down
191 changes: 111 additions & 80 deletions src/core/internal/convert.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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_;
Expand Down Expand Up @@ -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_;
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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
{
Expand All @@ -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)
{
Expand All @@ -618,114 +634,129 @@ 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
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
{
return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
}
}

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

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))
@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)
{
foreach (cur; T.init.tupleof)
if (__ctfe)
{
static if (!isNonReference!(typeof(cur))()) return false;
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];
}

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 == struct) || is(T == union))
{
if (__ctfe)
{
ubyte[T.sizeof] bytes;
foreach (key, cur; val.tupleof)
ubyte[] bytes = ctfe_alloc(T.sizeof);
foreach (key, ref 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)))
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)))
{
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
bytes[val.tupleof[key].offsetof .. val.tupleof[key].offsetof + CurType.sizeof] = toUbyte(cur)[];
}
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");
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[].dup;
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;
}
Loading