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

Convert _d_arraycast to template #2264

Merged
merged 1 commit into from
Aug 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making sure that @Geod24's suggestion in #2264 (comment) isn't lost:

version (D_NoBoundsChecks) {}
else if ((fromSize % TTo.sizeof) != 0)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm waiting to find out what happens with dlang/dmd#8532. I don't think it should hold up this PR, and would even be better if it were done in a followup PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair.

{
onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
}

struct Array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need static?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there is no functions, it does not

{
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);
}