diff --git a/mak/COPY b/mak/COPY index 2de8a3c228..0e2265fc66 100644 --- a/mak/COPY +++ b/mak/COPY @@ -405,5 +405,6 @@ COPY=\ \ $(IMPDIR)\rt\array\comparison.d \ $(IMPDIR)\rt\array\equality.d \ + $(IMPDIR)\rt\array\casting.d \ \ $(IMPDIR)\etc\linux\memoryerror.d diff --git a/mak/SRCS b/mak/SRCS index e068b323c1..23144ed002 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -453,6 +453,7 @@ SRCS=\ \ src\rt\array\comparison.d \ src\rt\array\equality.d \ + src\rt\array\casting.d \ \ src\rt\backtrace\dwarf.d \ src\rt\backtrace\elf.d \ diff --git a/mak/WINDOWS b/mak/WINDOWS index 276aa9e424..a1b75a356e 100644 --- a/mak/WINDOWS +++ b/mak/WINDOWS @@ -1193,3 +1193,6 @@ $(IMPDIR)\rt\array\comparison.d : src\rt\array\comparison.d $(IMPDIR)\rt\array\equality.d : src\rt\array\equality.d copy $** $@ + +$(IMPDIR)\rt\array\casting.d : src\rt\array\casting.d + copy $** $@ diff --git a/src/object.d b/src/object.d index 97a8e5e9cd..f7850b0a8a 100644 --- a/src/object.d +++ b/src/object.d @@ -40,6 +40,7 @@ version (D_ObjectiveC) public import core.attribute : selector; public import rt.array.comparison : __cmp; public import rt.array.equality : __ArrayEq, __equals; +public import rt.array.casting: __ArrayCast; // Compare class and interface objects for ordering. private int __cmp(Obj)(Obj lhs, Obj rhs) @@ -4398,111 +4399,6 @@ void __ArrayDtor(T)(T[] 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; - - const(char)[][9] msgComponents = - [ - "An array of size " - , unsignedToTempString(fromSize) - , " does not align on an array of size " - , unsignedToTempString(toSize) - , ", so `" - , fromType - , "` cannot be cast to `" - , toType - , "`" - ]; - - // convert discontiguous `msgComponents` to contiguous string on the stack - enum msgLength = 2048; - char[msgLength] msg; - - size_t index = 0; - foreach (m; msgComponents) - { - foreach (c; m) - { - msg[index++] = c; - if (index >= (msgLength - 1)) - break; - } - - if (index >= (msgLength - 1)) - break; - } - msg[index] = '\0'; // null-termination - - // 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); -} - // Allows customized assert error messages string _d_assert_fail(string comp, A, B)(A a, B b) @nogc @safe nothrow pure { diff --git a/src/rt/array/casting.d b/src/rt/array/casting.d new file mode 100644 index 0000000000..d8ca79af2d --- /dev/null +++ b/src/rt/array/casting.d @@ -0,0 +1,115 @@ +/** + This module contains compiler support for casting dynamic arrays + + Copyright: Copyright Digital Mars 2000 - 2019. + License: Distributed under the + $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). + (See accompanying file LICENSE) + Source: $(DRUNTIMESRC rt/_array/_casting.d) +*/ +module rt.array.casting; + +/** +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; + + const(char)[][9] msgComponents = + [ + "An array of size " + , unsignedToTempString(fromSize) + , " does not align on an array of size " + , unsignedToTempString(toSize) + , ", so `" + , fromType + , "` cannot be cast to `" + , toType + , "`" + ]; + + // convert discontiguous `msgComponents` to contiguous string on the stack + enum msgLength = 2048; + char[msgLength] msg; + + size_t index = 0; + foreach (m; msgComponents) + { + foreach (c; m) + { + msg[index++] = c; + if (index >= (msgLength - 1)) + break; + } + + if (index >= (msgLength - 1)) + break; + } + msg[index] = '\0'; // null-termination + + // 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); +}