Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit f2e7956

Browse files
authored
Merge pull request #2264 from JinShil/lower_array_cast
Convert _d_arraycast to template merged-on-behalf-of: unknown
2 parents 69ae3dc + 2aed104 commit f2e7956

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

src/core/internal/string.d

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,20 @@ nothrow:
1515

1616
alias UnsignedStringBuf = char[20];
1717

18-
char[] unsignedToTempString(ulong value, return scope char[] buf, uint radix = 10) @safe
18+
/**
19+
Converts an unsigned integer value to a string of characters.
20+
21+
This implementation is a template so it can be used when compiling with -betterC.
22+
23+
Params:
24+
value = the unsigned integer value to convert
25+
buf = the pre-allocated buffer used to store the result
26+
radix = the numeric base to use in the conversion (defaults to 10)
27+
28+
Returns:
29+
The unsigned integer value as a string of characters
30+
*/
31+
char[] unsignedToTempString()(ulong value, return scope char[] buf, uint radix = 10) @safe
1932
{
2033
if (radix < 2)
2134
// not a valid radix, just return an empty string
@@ -52,7 +65,19 @@ private struct TempStringNoAlloc
5265
alias get this;
5366
}
5467

55-
auto unsignedToTempString(ulong value, uint radix = 10) @safe
68+
/**
69+
Converts an unsigned integer value to a string of characters.
70+
71+
This implementation is a template so it can be used when compiling with -betterC.
72+
73+
Params:
74+
value = the unsigned integer value to convert
75+
radix = the numeric base to use in the conversion (defaults to 10)
76+
77+
Returns:
78+
The unsigned integer value as a string of characters
79+
*/
80+
auto unsignedToTempString()(ulong value, uint radix = 10) @safe
5681
{
5782
TempStringNoAlloc result = void;
5883
result._len = unsignedToTempString(value, result._buf, radix).length & 0xff;

src/object.d

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4881,3 +4881,101 @@ void __ArrayDtor(T)(T[] a)
48814881
foreach_reverse (ref T e; a)
48824882
e.__xdtor();
48834883
}
4884+
4885+
/**
4886+
Used by `__ArrayCast` to emit a descriptive error message.
4887+
4888+
It is a template so it can be used by `__ArrayCast` in -betterC
4889+
builds. It is separate from `__ArrayCast` to minimize code
4890+
bloat.
4891+
4892+
Params:
4893+
fromType = name of the type being cast from
4894+
fromSize = total size in bytes of the array being cast from
4895+
toType = name of the type being cast o
4896+
toSize = total size in bytes of the array being cast to
4897+
*/
4898+
private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted
4899+
{
4900+
import core.internal.string : unsignedToTempString;
4901+
import core.stdc.stdlib : alloca;
4902+
4903+
const(char)[][8] msgComponents =
4904+
[
4905+
"Cannot cast `"
4906+
, fromType
4907+
, "` to `"
4908+
, toType
4909+
, "`; an array of size "
4910+
, unsignedToTempString(fromSize)
4911+
, " does not align on an array of size "
4912+
, unsignedToTempString(toSize)
4913+
];
4914+
4915+
// convert discontiguous `msgComponents` to contiguous string on the stack
4916+
size_t length = 0;
4917+
foreach (m ; msgComponents)
4918+
length += m.length;
4919+
4920+
auto msg = (cast(char*)alloca(length))[0 .. length];
4921+
4922+
size_t index = 0;
4923+
foreach (m ; msgComponents)
4924+
foreach (c; m)
4925+
msg[index++] = c;
4926+
4927+
// first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
4928+
assert(false, msg);
4929+
}
4930+
4931+
/**
4932+
The compiler lowers expressions of `cast(TTo[])TFrom[]` to
4933+
this implementation.
4934+
4935+
Params:
4936+
from = the array to reinterpret-cast
4937+
4938+
Returns:
4939+
`from` reinterpreted as `TTo[]`
4940+
*/
4941+
TTo[] __ArrayCast(TFrom, TTo)(TFrom[] from) @nogc pure @trusted
4942+
{
4943+
const fromSize = from.length * TFrom.sizeof;
4944+
const toLength = fromSize / TTo.sizeof;
4945+
4946+
if ((fromSize % TTo.sizeof) != 0)
4947+
{
4948+
onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
4949+
}
4950+
4951+
struct Array
4952+
{
4953+
size_t length;
4954+
void* ptr;
4955+
}
4956+
auto a = cast(Array*)&from;
4957+
a.length = toLength; // jam new length
4958+
return *cast(TTo[]*)a;
4959+
}
4960+
4961+
@safe @nogc pure nothrow unittest
4962+
{
4963+
byte[int.sizeof * 3] b = cast(byte) 0xab;
4964+
int[] i;
4965+
short[] s;
4966+
4967+
i = __ArrayCast!(byte, int)(b);
4968+
assert(i.length == 3);
4969+
foreach (v; i)
4970+
assert(v == cast(int) 0xabab_abab);
4971+
4972+
s = __ArrayCast!(byte, short)(b);
4973+
assert(s.length == 6);
4974+
foreach (v; s)
4975+
assert(v == cast(short) 0xabab);
4976+
4977+
s = __ArrayCast!(int, short)(i);
4978+
assert(s.length == 6);
4979+
foreach (v; s)
4980+
assert(v == cast(short) 0xabab);
4981+
}

0 commit comments

Comments
 (0)