1 /**
2 This module contains compiler support for casting dynamic arrays
3
4 Copyright: Copyright Digital Mars 2000 - 2019.
5 License: Distributed under the
6 $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7 (See accompanying file LICENSE)
8 Source: $(DRUNTIMESRC core/internal/_array/_casting.d)
9 */
10 module core.internal.array.casting;
11
12 /**
13 Used by `__ArrayCast` to emit a descriptive error message.
14
15 It is a template so it can be used by `__ArrayCast` in -betterC
16 builds. It is separate from `__ArrayCast` to minimize code
17 bloat.
18
19 Params:
20 fromType = name of the type being cast from
21 fromSize = total size in bytes of the array being cast from
22 toType = name of the type being cast o
23 toSize = total size in bytes of the array being cast to
24 */
onArrayCastError()25 private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted
26 {
27 import core.internal.string : unsignedToTempString;
28 import core.memory : pureMalloc;
29
30 // convert discontiguous `msgComponents` to contiguous string on the C heap
31 enum msgLength = 2048;
32 // note: never freed!
33 char* msg = cast(char *)pureMalloc(msgLength);
34
35 size_t index = 0;
36 void add(const(char)[] m)
37 {
38 import core.stdc.string : memcpy;
39
40 auto N = msgLength - 1 - index;
41 if (N > m.length)
42 N = m.length;
43 // prevent superfluous and betterC-unfriendly checks via direct memcpy
44 memcpy(msg + index, m.ptr, N);
45 index += N;
46 }
47
48 add("An array of size ");
49 auto s = unsignedToTempString(fromSize);
50 add(s[]);
51 add(" does not align on an array of size ");
52 s = unsignedToTempString(toSize);
53 add(s[]);
54 add(", so `");
55 add(fromType);
56 add("` cannot be cast to `");
57 add(toType);
58 add("`");
59 msg[index] = '\0'; // null-termination
60
61 // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
62 assert(false, msg[0 .. index]);
63 }
64
65 /**
66 The compiler lowers expressions of `cast(TTo[])TFrom[]` to
67 this implementation.
68
69 Params:
70 from = the array to reinterpret-cast
71
72 Returns:
73 `from` reinterpreted as `TTo[]`
74 */
__ArrayCast(TFrom,TTo)75 TTo[] __ArrayCast(TFrom, TTo)(return scope TFrom[] from) @nogc pure @trusted
76 {
77 const fromSize = from.length * TFrom.sizeof;
78 const toLength = fromSize / TTo.sizeof;
79
80 if ((fromSize % TTo.sizeof) != 0)
81 {
82 onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
83 }
84
85 struct Array
86 {
87 size_t length;
88 void* ptr;
89 }
90 auto a = cast(Array*)&from;
91 a.length = toLength; // jam new length
92 return *cast(TTo[]*)a;
93 }
94
95 @safe @nogc pure nothrow unittest
96 {
97 byte[int.sizeof * 3] b = cast(byte) 0xab;
98 int[] i;
99 short[] s;
100
101 i = __ArrayCast!(byte, int)(b);
102 assert(i.length == 3);
103 foreach (v; i)
104 assert(v == cast(int) 0xabab_abab);
105
106 s = __ArrayCast!(byte, short)(b);
107 assert(s.length == 6);
108 foreach (v; s)
109 assert(v == cast(short) 0xabab);
110
111 s = __ArrayCast!(int, short)(i);
112 assert(s.length == 6);
113 foreach (v; s)
114 assert(v == cast(short) 0xabab);
115 }
116