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

Commit

Permalink
Merge pull request #2264 from JinShil/lower_array_cast
Browse files Browse the repository at this point in the history
Convert _d_arraycast to template
merged-on-behalf-of: unknown
  • Loading branch information
dlang-bot authored Aug 11, 2018
2 parents 69ae3dc + 2aed104 commit f2e7956
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 2 deletions.
29 changes: 27 additions & 2 deletions src/core/internal/string.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
98 changes: 98 additions & 0 deletions src/object.d
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit f2e7956

Please sign in to comment.