From 2aed1042c633516e236f21b9dd39fd3f472b65bf Mon Sep 17 00:00:00 2001 From: JinShil Date: Thu, 2 Aug 2018 12:13:23 +0900 Subject: [PATCH] Convert _d_arraycast to template --- src/core/internal/string.d | 29 ++++++++++- src/object.d | 98 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 2 deletions(-) diff --git a/src/core/internal/string.d b/src/core/internal/string.d index d51f1fdead..497a7e88ec 100644 --- a/src/core/internal/string.d +++ b/src/core/internal/string.d @@ -15,7 +15,20 @@ nothrow: alias UnsignedStringBuf = char[20]; -char[] unsignedToTempString(ulong value, return scope char[] buf, uint radix = 10) @safe +/** +Converts an unsigned integer value to a string of characters. + +This implementation is a template so it can be used when compiling with -betterC. + +Params: + value = the unsigned integer value to convert + buf = the pre-allocated buffer used to store the result + radix = the numeric base to use in the conversion (defaults to 10) + +Returns: + The unsigned integer value as a string of characters +*/ +char[] unsignedToTempString()(ulong value, return scope char[] buf, uint radix = 10) @safe { if (radix < 2) // not a valid radix, just return an empty string @@ -52,7 +65,19 @@ private struct TempStringNoAlloc alias get this; } -auto unsignedToTempString(ulong value, uint radix = 10) @safe +/** +Converts an unsigned integer value to a string of characters. + +This implementation is a template so it can be used when compiling with -betterC. + +Params: + value = the unsigned integer value to convert + radix = the numeric base to use in the conversion (defaults to 10) + +Returns: + The unsigned integer value as a string of characters +*/ +auto unsignedToTempString()(ulong value, uint radix = 10) @safe { TempStringNoAlloc result = void; result._len = unsignedToTempString(value, result._buf, radix).length & 0xff; diff --git a/src/object.d b/src/object.d index 3653103590..e69001be7b 100644 --- a/src/object.d +++ b/src/object.d @@ -4881,3 +4881,101 @@ void __ArrayDtor(T)(T[] a) foreach_reverse (ref T e; a) e.__xdtor(); } + +/** +Used by `__ArrayCast` to emit a descriptive error message. + +It is a template so it can be used by `__ArrayCast` in -betterC +builds. It is separate from `__ArrayCast` to minimize code +bloat. + +Params: + fromType = name of the type being cast from + fromSize = total size in bytes of the array being cast from + toType = name of the type being cast o + toSize = total size in bytes of the array being cast to + */ +private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted +{ + import core.internal.string : unsignedToTempString; + import core.stdc.stdlib : alloca; + + const(char)[][8] msgComponents = + [ + "Cannot cast `" + , fromType + , "` to `" + , toType + , "`; an array of size " + , unsignedToTempString(fromSize) + , " does not align on an array of size " + , unsignedToTempString(toSize) + ]; + + // convert discontiguous `msgComponents` to contiguous string on the stack + size_t length = 0; + foreach (m ; msgComponents) + length += m.length; + + auto msg = (cast(char*)alloca(length))[0 .. length]; + + size_t index = 0; + foreach (m ; msgComponents) + foreach (c; m) + msg[index++] = c; + + // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds + assert(false, msg); +} + +/** +The compiler lowers expressions of `cast(TTo[])TFrom[]` to +this implementation. + +Params: + from = the array to reinterpret-cast + +Returns: + `from` reinterpreted as `TTo[]` + */ +TTo[] __ArrayCast(TFrom, TTo)(TFrom[] from) @nogc pure @trusted +{ + const fromSize = from.length * TFrom.sizeof; + const toLength = fromSize / TTo.sizeof; + + if ((fromSize % TTo.sizeof) != 0) + { + onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof); + } + + struct Array + { + size_t length; + void* ptr; + } + auto a = cast(Array*)&from; + a.length = toLength; // jam new length + return *cast(TTo[]*)a; +} + +@safe @nogc pure nothrow unittest +{ + byte[int.sizeof * 3] b = cast(byte) 0xab; + int[] i; + short[] s; + + i = __ArrayCast!(byte, int)(b); + assert(i.length == 3); + foreach (v; i) + assert(v == cast(int) 0xabab_abab); + + s = __ArrayCast!(byte, short)(b); + assert(s.length == 6); + foreach (v; s) + assert(v == cast(short) 0xabab); + + s = __ArrayCast!(int, short)(i); + assert(s.length == 6); + foreach (v; s) + assert(v == cast(short) 0xabab); +}