Skip to content

Commit c46ab08

Browse files
committed
Fixes Issue 16745 - Add template helper for creating static arrays with the size inferred
1 parent 4c843be commit c46ab08

File tree

1 file changed

+284
-0
lines changed

1 file changed

+284
-0
lines changed

std/array.d

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import std.meta;
8181
import std.traits;
8282

8383
import std.range.primitives;
84+
import std.conv : emplaceRef;
8485
public import std.range.primitives : save, empty, popFront, popBack, front, back;
8586

8687
/**
@@ -3891,3 +3892,286 @@ unittest
38913892
assert(appS.data == "hellow");
38923893
assert(appA.data == "hellow");
38933894
}
3895+
3896+
/++
3897+
Params: a = The array elements
3898+
3899+
Returns: A static array constructed from `a`.The type of elements can be
3900+
specified implicitly (`int[2] a = staticArray(1,2);`) or explicitly
3901+
(`float[2] a = staticArray!float(1,2)`).
3902+
The result is an rvalue, therefore uses like
3903+
`foo(staticArray(1, 2, 3))` may be inefficient because of the copies.
3904+
+/
3905+
pragma(inline, true) U[T.length] staticArray(U = CommonType!T, T...)(T a) nothrow @safe pure @nogc
3906+
{
3907+
return [a];
3908+
}
3909+
3910+
/// ditto
3911+
// Workaround https://issues.dlang.org/show_bug.cgi?id=16779 (make alias to staticArray once fixed)
3912+
pragma(inline, true) U[T.length] staticArrayCast(U, T...)(T a) nothrow @safe pure @nogc
3913+
{
3914+
enum n = T.length;
3915+
U[n] ret = void;
3916+
static foreach (i; 0 .. n)
3917+
{
3918+
// TODO: If any of these throws, the destructors of the already-constructed elements is not called. https://github.com/dlang/phobos/pull/4936/files#r131709329
3919+
emplaceRef!U(ret[i], cast(U) a[i]);
3920+
}
3921+
return ret;
3922+
}
3923+
3924+
///
3925+
nothrow pure @safe unittest
3926+
{
3927+
auto a = staticArray(1, 2);
3928+
assert(is(typeof(a) == int[2]) && a == [1, 2]);
3929+
3930+
auto b = staticArrayCast!byte(1, 2);
3931+
assert(is(typeof(b) == byte[2]) && b == [1, 2]);
3932+
}
3933+
3934+
nothrow pure @safe unittest
3935+
{
3936+
int val = 3;
3937+
staticArray(1, 2, val).checkStaticArray!int([1, 2, 3]);
3938+
staticArray(1, 2.0).checkStaticArray!double([1, 2.0]);
3939+
assert(!__traits(compiles, staticArray(1, "")));
3940+
staticArray().checkStaticArray!void([]);
3941+
staticArray!float(1, 2).checkStaticArray!float([1, 2]);
3942+
// auto a = staticArray!byte(1, 2);
3943+
staticArrayCast!byte(1, 2).checkStaticArray!byte([1, 2]);
3944+
staticArrayCast!byte(1, 129).checkStaticArray!byte([1, -127]);
3945+
3946+
staticArrayCast!(const(int))(1, 2).checkStaticArray!(const(int))([1, 2]);
3947+
staticArrayCast!(immutable(int))(1, 2).checkStaticArray!(immutable(int))([1, 2]);
3948+
staticArray([1]).checkStaticArray!(int[])([[1]]);
3949+
}
3950+
3951+
@system unittest
3952+
{
3953+
version (Bug)
3954+
{
3955+
// NOTE: correctly issues a deprecation
3956+
int[] a2 = staticArray(1, 2);
3957+
}
3958+
}
3959+
3960+
/++
3961+
Params: arr = The array elements
3962+
3963+
Returns: A static array constructed from `arr`. The type of elements can be
3964+
specified implicitly (`int[2] a = [1,2].asStatic;`) or explicitly
3965+
(`float[2] a = [1,2].asStaticCast!float`).
3966+
+/
3967+
pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc
3968+
{
3969+
return arr;
3970+
}
3971+
3972+
/// ditto
3973+
U[n] asStaticCast(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc
3974+
{
3975+
U[n] ret = void;
3976+
static foreach (i; 0 .. n)
3977+
{
3978+
emplaceRef!U(ret[i], cast(U) arr[i]);
3979+
}
3980+
return ret;
3981+
}
3982+
3983+
///
3984+
nothrow pure @safe unittest
3985+
{
3986+
auto a = [0, 1].asStatic;
3987+
assert(is(typeof(a) == int[2]) && a == [0, 1]);
3988+
3989+
auto b = [0, 1].asStaticCast!byte;
3990+
assert(is(typeof(b) == byte[2]) && b == [0, 1]);
3991+
}
3992+
3993+
nothrow pure @safe unittest
3994+
{
3995+
int val = 3;
3996+
static immutable gold = [1, 2, 3];
3997+
[1, 2, val].asStatic.checkStaticArray!int([1, 2, 3]);
3998+
3999+
@nogc void checkNogc()
4000+
{
4001+
[1, 2, val].asStatic.checkStaticArray!int(gold);
4002+
}
4003+
4004+
[1, 2, val].asStaticCast!double.checkStaticArray!double(gold);
4005+
[1, 2, 3].asStaticCast!int.checkStaticArray!int(gold);
4006+
4007+
[1, 2, 3].asStaticCast!(const(int)).checkStaticArray!(const(int))(gold);
4008+
[1, 2, 3].asStaticCast!(const(double)).checkStaticArray!(const(double))(gold);
4009+
{
4010+
const(int)[3] a2 = [1, 2, 3].asStatic;
4011+
}
4012+
4013+
[1, 129].asStaticCast!byte.checkStaticArray!byte([1, -127]);
4014+
4015+
}
4016+
4017+
/++
4018+
Params: a = input range of elements
4019+
4020+
Returns: A static array constructed from `a`.
4021+
+/
4022+
auto asStatic(size_t n, T)(T a) nothrow @safe pure @nogc
4023+
{
4024+
// TODO: ElementType vs ForeachType
4025+
alias U = typeof(a[0]);
4026+
U[n] ret = void;
4027+
size_t i;
4028+
foreach (ref ai; a)
4029+
{
4030+
emplaceRef!U(ret[i++], ai);
4031+
}
4032+
assert(i == n);
4033+
return ret;
4034+
}
4035+
4036+
/// ditto
4037+
auto asStaticCast(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc
4038+
{
4039+
U[n] ret = void;
4040+
size_t i;
4041+
foreach (ref ai; a)
4042+
{
4043+
emplaceRef!U(ret[i++], cast(U) ai);
4044+
}
4045+
assert(i == n);
4046+
return ret;
4047+
}
4048+
4049+
///
4050+
nothrow pure @safe unittest
4051+
{
4052+
import std.range : iota;
4053+
4054+
auto a = 2.iota.asStatic!2;
4055+
assert(is(typeof(a) == int[2]) && a == [0, 1]);
4056+
auto b = 2.iota.asStaticCast!(byte[2]);
4057+
assert(is(typeof(b) == byte[2]) && b == [0, 1]);
4058+
}
4059+
4060+
nothrow pure @safe unittest
4061+
{
4062+
4063+
auto a = [1, 2].asStatic;
4064+
assert(is(typeof(a) == int[2]) && a == [1, 2]);
4065+
4066+
import std.range : iota;
4067+
4068+
2.iota.asStatic!2.checkStaticArray!int([0, 1]);
4069+
2.iota.asStaticCast!(double[2]).checkStaticArray!double([0, 1]);
4070+
2.iota.asStaticCast!(byte[2]).checkStaticArray!byte([0, 1]);
4071+
}
4072+
4073+
nothrow pure @system unittest
4074+
{
4075+
import std.range : iota;
4076+
4077+
assert(isThrown!Error(2.iota.asStatic!1));
4078+
assert(isThrown!Error(2.iota.asStatic!3));
4079+
// NOTE: alternatives are not nothrow:
4080+
version (none)
4081+
{
4082+
import std.exception : assertThrown;
4083+
4084+
assertThrown!Error(2.iota.asStatic!3);
4085+
import std.exception : ifThrown;
4086+
4087+
assert(ifThrown!Error({ 2.iota.asStatic!1; return false; }(), true));
4088+
}
4089+
}
4090+
4091+
@system unittest
4092+
{
4093+
version (Bug)
4094+
{
4095+
// https://issues.dlang.org/show_bug.cgi?id=16779
4096+
auto a2 = [1, 2, 3].asStatic!byte;
4097+
auto a3 = [1, 2, 3].asStatic!ubyte;
4098+
4099+
// NOTE: correctly issues a deprecation
4100+
int[] a2 = [1, 2].asStatic;
4101+
}
4102+
}
4103+
4104+
/++
4105+
Params: arr = the compile time range
4106+
4107+
Returns: A static array constructed from `arr`.
4108+
+/
4109+
auto asStatic(alias arr)() nothrow @safe pure @nogc
4110+
{
4111+
enum n = arr.length;
4112+
alias U = typeof(arr[0]);
4113+
U[n] ret = void;
4114+
static foreach (i; 0 .. n)
4115+
{
4116+
emplaceRef!U(ret[i], arr[i]);
4117+
}
4118+
return ret;
4119+
}
4120+
4121+
/// ditto
4122+
auto asStaticCast(U, alias arr)() nothrow @safe pure @nogc
4123+
{
4124+
enum n = arr.length;
4125+
U[n] ret = void;
4126+
static foreach (i; 0 .. n)
4127+
{
4128+
emplaceRef!U(ret[i], cast(U) arr[i]);
4129+
}
4130+
return ret;
4131+
}
4132+
4133+
///
4134+
nothrow pure @safe unittest
4135+
{
4136+
import std.range : iota;
4137+
4138+
enum a = asStatic!(2.iota);
4139+
assert(is(typeof(a) == int[2]) && a == [0, 1]);
4140+
4141+
enum b = asStaticCast!(byte, 2.iota);
4142+
assert(is(typeof(b) == byte[2]) && b == [0, 1]);
4143+
}
4144+
4145+
nothrow pure @safe unittest
4146+
{
4147+
import std.range : iota;
4148+
4149+
enum a = asStatic!(2.iota);
4150+
asStatic!(2.iota).checkStaticArray!int([0, 1]);
4151+
asStaticCast!(double, 2.iota).checkStaticArray!double([0, 1]);
4152+
asStaticCast!(byte, 2.iota).checkStaticArray!byte([0, 1]);
4153+
}
4154+
4155+
void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc
4156+
{
4157+
assert(is(T1 == T[T1.length]));
4158+
assert(a == b);
4159+
}
4160+
4161+
// TODO: add this to assertThrown in std.exception
4162+
bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow pure @system
4163+
{
4164+
try
4165+
{
4166+
expression();
4167+
return false;
4168+
}
4169+
catch (T)
4170+
{
4171+
return true;
4172+
}
4173+
catch (Exception)
4174+
{
4175+
return false;
4176+
}
4177+
}

0 commit comments

Comments
 (0)