| /** |
| 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 core/internal/_array/_casting.d) |
| */ |
| module core.internal.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 |
| fromLength = length of array being cast from |
| toType = name of the type being cast to |
| toElemSize = element size of array being cast to |
| */ |
| private void onArrayCastError()(string fromType, size_t fromSize, size_t fromLength, string toType, size_t toElemSize) @trusted |
| { |
| import core.internal.string : unsignedToTempString; |
| import core.memory : pureMalloc; |
| |
| // convert discontiguous `msgComponents` to contiguous string on the C heap |
| enum msgLength = 2048; |
| // note: never freed! |
| char* msg = cast(char *)pureMalloc(msgLength); |
| |
| size_t index = 0; |
| void add(const(char)[] m) |
| { |
| import core.stdc.string : memcpy; |
| |
| auto N = msgLength - 1 - index; |
| if (N > m.length) |
| N = m.length; |
| // prevent superfluous and betterC-unfriendly checks via direct memcpy |
| memcpy(msg + index, m.ptr, N); |
| index += N; |
| } |
| |
| add("`"); |
| add(fromType); |
| add("[]` of length "); |
| auto s = unsignedToTempString(fromLength); |
| add(s[]); |
| add(" cannot be cast to `"); |
| add(toType); |
| add("[]` as its length in bytes ("); |
| s = unsignedToTempString(fromSize); |
| add(s[]); |
| add(") is not a multiple of `"); |
| add(toType); |
| add(".sizeof` ("); |
| s = unsignedToTempString(toElemSize); |
| add(s[]); |
| add(")."); |
| msg[index] = '\0'; // null-termination |
| |
| // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds |
| assert(false, msg[0 .. index]); |
| } |
| |
| /** |
| The compiler lowers expressions of `cast(TTo[])TFrom[]` to |
| this implementation. Note that this does not detect alignment problems. |
| |
| Params: |
| from = the array to reinterpret-cast |
| |
| Returns: |
| `from` reinterpreted as `TTo[]` |
| */ |
| TTo[] __ArrayCast(TFrom, TTo)(return scope 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, from.length, TTo.stringof, 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); |
| } |
| |
| @system nothrow unittest |
| { |
| string msg; |
| try |
| { |
| auto str = "hello"; |
| auto wstr = cast(wstring) str; |
| } |
| catch (Throwable t) |
| msg = t.msg; |
| |
| static immutable expected = "`immutable(char)[]` of length 5 cannot be cast to `immutable(wchar)[]` as " ~ |
| "its length in bytes (5) is not a multiple of `immutable(wchar).sizeof` (2)."; |
| |
| if (msg != expected) |
| { |
| import core.stdc.stdio : printf; |
| printf("Expected: |%.*s|\n", cast(int) expected.length, expected.ptr); |
| printf("Actual : |%.*s|\n", cast(int) msg.length, msg.ptr); |
| assert(false); |
| } |
| } |