From 3573814950d677a450fe6743024af9c6b55055d3 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Feb 2018 21:11:19 -0800 Subject: [PATCH 01/23] Fixes Issue 16745 - Add template helper for creating static arrays with the size inferred --- std/array.d | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) diff --git a/std/array.d b/std/array.d index a6888a35af2..ee3958fedf9 100644 --- a/std/array.d +++ b/std/array.d @@ -82,6 +82,7 @@ import std.meta; import std.traits; import std.range.primitives; +import std.conv : emplaceRef; public import std.range.primitives : save, empty, popFront, popBack, front, back; /** @@ -3927,3 +3928,286 @@ unittest assert(appS.data == "hellow"); assert(appA.data == "hellow"); } + +/++ +Params: a = The array elements + +Returns: A static array constructed from `a`. The type of elements can be +specified implicitly (`int[2] a = staticArray(1,2);`) or explicitly +(`float[2] a = staticArray!float(1,2)`). +The result is an rvalue, therefore uses like +`foo(staticArray(1, 2, 3))` may be inefficient because of the copies. ++/ +pragma(inline, true) U[T.length] staticArray(U = CommonType!T, T...)(T a) nothrow @safe pure @nogc +{ + return [a]; +} + +/// ditto +// Workaround https://issues.dlang.org/show_bug.cgi?id=16779 (make alias to staticArray once fixed) +pragma(inline, true) U[T.length] staticArrayCast(U, T...)(T a) nothrow @safe pure @nogc +{ + enum n = T.length; + U[n] ret = void; + static foreach (i; 0 .. n) + { + // 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 + emplaceRef!U(ret[i], cast(U) a[i]); + } + return ret; +} + +/// +nothrow pure @safe unittest +{ + auto a = staticArray(1, 2); + assert(is(typeof(a) == int[2]) && a == [1, 2]); + + auto b = staticArrayCast!byte(1, 2); + assert(is(typeof(b) == byte[2]) && b == [1, 2]); +} + +nothrow pure @safe unittest +{ + int val = 3; + staticArray(1, 2, val).checkStaticArray!int([1, 2, 3]); + staticArray(1, 2.0).checkStaticArray!double([1, 2.0]); + assert(!__traits(compiles, staticArray(1, ""))); + staticArray().checkStaticArray!void([]); + staticArray!float(1, 2).checkStaticArray!float([1, 2]); + // auto a = staticArray!byte(1, 2); + staticArrayCast!byte(1, 2).checkStaticArray!byte([1, 2]); + staticArrayCast!byte(1, 129).checkStaticArray!byte([1, -127]); + + staticArrayCast!(const(int))(1, 2).checkStaticArray!(const(int))([1, 2]); + staticArrayCast!(immutable(int))(1, 2).checkStaticArray!(immutable(int))([1, 2]); + staticArray([1]).checkStaticArray!(int[])([[1]]); +} + +@system unittest +{ + version (Bug) + { + // NOTE: correctly issues a deprecation + int[] a2 = staticArray(1, 2); + } +} + +/++ +Params: arr = The array elements + +Returns: A static array constructed from `arr`. The type of elements can be +specified implicitly (`int[2] a = [1,2].asStatic;`) or explicitly +(`float[2] a = [1,2].asStaticCast!float`). ++/ +pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc +{ + return arr; +} + +/// ditto +U[n] asStaticCast(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc +{ + U[n] ret = void; + static foreach (i; 0 .. n) + { + emplaceRef!U(ret[i], cast(U) arr[i]); + } + return ret; +} + +/// +nothrow pure @safe unittest +{ + auto a = [0, 1].asStatic; + assert(is(typeof(a) == int[2]) && a == [0, 1]); + + auto b = [0, 1].asStaticCast!byte; + assert(is(typeof(b) == byte[2]) && b == [0, 1]); +} + +nothrow pure @safe unittest +{ + int val = 3; + static immutable gold = [1, 2, 3]; + [1, 2, val].asStatic.checkStaticArray!int([1, 2, 3]); + + @nogc void checkNogc() + { + [1, 2, val].asStatic.checkStaticArray!int(gold); + } + + [1, 2, val].asStaticCast!double.checkStaticArray!double(gold); + [1, 2, 3].asStaticCast!int.checkStaticArray!int(gold); + + [1, 2, 3].asStaticCast!(const(int)).checkStaticArray!(const(int))(gold); + [1, 2, 3].asStaticCast!(const(double)).checkStaticArray!(const(double))(gold); + { + const(int)[3] a2 = [1, 2, 3].asStatic; + } + + [1, 129].asStaticCast!byte.checkStaticArray!byte([1, -127]); + +} + +/++ +Params: a = input range of elements + +Returns: A static array constructed from `a`. ++/ +auto asStatic(size_t n, T)(T a) nothrow @safe pure @nogc +{ + // TODO: ElementType vs ForeachType + alias U = typeof(a[0]); + U[n] ret = void; + size_t i; + foreach (ref ai; a) + { + emplaceRef!U(ret[i++], ai); + } + assert(i == n); + return ret; +} + +/// ditto +auto asStaticCast(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc +{ + U[n] ret = void; + size_t i; + foreach (ref ai; a) + { + emplaceRef!U(ret[i++], cast(U) ai); + } + assert(i == n); + return ret; +} + +/// +nothrow pure @safe unittest +{ + import std.range : iota; + + auto a = 2.iota.asStatic!2; + assert(is(typeof(a) == int[2]) && a == [0, 1]); + auto b = 2.iota.asStaticCast!(byte[2]); + assert(is(typeof(b) == byte[2]) && b == [0, 1]); +} + +nothrow pure @safe unittest +{ + + auto a = [1, 2].asStatic; + assert(is(typeof(a) == int[2]) && a == [1, 2]); + + import std.range : iota; + + 2.iota.asStatic!2.checkStaticArray!int([0, 1]); + 2.iota.asStaticCast!(double[2]).checkStaticArray!double([0, 1]); + 2.iota.asStaticCast!(byte[2]).checkStaticArray!byte([0, 1]); +} + +nothrow pure @system unittest +{ + import std.range : iota; + + assert(isThrown!Error(2.iota.asStatic!1)); + assert(isThrown!Error(2.iota.asStatic!3)); + // NOTE: alternatives are not nothrow: + version (none) + { + import std.exception : assertThrown; + + assertThrown!Error(2.iota.asStatic!3); + import std.exception : ifThrown; + + assert(ifThrown!Error({ 2.iota.asStatic!1; return false; }(), true)); + } +} + +@system unittest +{ + version (Bug) + { + // https://issues.dlang.org/show_bug.cgi?id=16779 + auto a2 = [1, 2, 3].asStatic!byte; + auto a3 = [1, 2, 3].asStatic!ubyte; + + // NOTE: correctly issues a deprecation + int[] a2 = [1, 2].asStatic; + } +} + +/++ +Params: arr = the compile time range + +Returns: A static array constructed from `arr`. ++/ +auto asStatic(alias arr)() nothrow @safe pure @nogc +{ + enum n = arr.length; + alias U = typeof(arr[0]); + U[n] ret = void; + static foreach (i; 0 .. n) + { + emplaceRef!U(ret[i], arr[i]); + } + return ret; +} + +/// ditto +auto asStaticCast(U, alias arr)() nothrow @safe pure @nogc +{ + enum n = arr.length; + U[n] ret = void; + static foreach (i; 0 .. n) + { + emplaceRef!U(ret[i], cast(U) arr[i]); + } + return ret; +} + +/// +nothrow pure @safe unittest +{ + import std.range : iota; + + enum a = asStatic!(2.iota); + assert(is(typeof(a) == int[2]) && a == [0, 1]); + + enum b = asStaticCast!(byte, 2.iota); + assert(is(typeof(b) == byte[2]) && b == [0, 1]); +} + +nothrow pure @safe unittest +{ + import std.range : iota; + + enum a = asStatic!(2.iota); + asStatic!(2.iota).checkStaticArray!int([0, 1]); + asStaticCast!(double, 2.iota).checkStaticArray!double([0, 1]); + asStaticCast!(byte, 2.iota).checkStaticArray!byte([0, 1]); +} + +void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc +{ + assert(is(T1 == T[T1.length])); + assert(a == b); +} + +// TODO: add this to assertThrown in std.exception +bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow pure @system +{ + try + { + expression(); + return false; + } + catch (T) + { + return true; + } + catch (Exception) + { + return false; + } +} From 5d55c902a7aa404f24cd47d5ad87fe37badfa59b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Mar 2018 14:53:18 -0700 Subject: [PATCH 02/23] address comments --- std/array.d | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/std/array.d b/std/array.d index ee3958fedf9..f025a729c09 100644 --- a/std/array.d +++ b/std/array.d @@ -82,7 +82,6 @@ import std.meta; import std.traits; import std.range.primitives; -import std.conv : emplaceRef; public import std.range.primitives : save, empty, popFront, popBack, front, back; /** @@ -3947,6 +3946,7 @@ pragma(inline, true) U[T.length] staticArray(U = CommonType!T, T...)(T a) nothro // Workaround https://issues.dlang.org/show_bug.cgi?id=16779 (make alias to staticArray once fixed) pragma(inline, true) U[T.length] staticArrayCast(U, T...)(T a) nothrow @safe pure @nogc { + import std.conv : emplaceRef; enum n = T.length; U[n] ret = void; static foreach (i; 0 .. n) @@ -4008,6 +4008,7 @@ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe /// ditto U[n] asStaticCast(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc { + import std.conv : emplaceRef; U[n] ret = void; static foreach (i; 0 .. n) { @@ -4057,6 +4058,7 @@ Returns: A static array constructed from `a`. +/ auto asStatic(size_t n, T)(T a) nothrow @safe pure @nogc { + import std.conv : emplaceRef; // TODO: ElementType vs ForeachType alias U = typeof(a[0]); U[n] ret = void; @@ -4072,6 +4074,7 @@ auto asStatic(size_t n, T)(T a) nothrow @safe pure @nogc /// ditto auto asStaticCast(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc { + import std.conv : emplaceRef; U[n] ret = void; size_t i; foreach (ref ai; a) @@ -4144,6 +4147,7 @@ Returns: A static array constructed from `arr`. +/ auto asStatic(alias arr)() nothrow @safe pure @nogc { + import std.conv : emplaceRef; enum n = arr.length; alias U = typeof(arr[0]); U[n] ret = void; @@ -4157,6 +4161,7 @@ auto asStatic(alias arr)() nothrow @safe pure @nogc /// ditto auto asStaticCast(U, alias arr)() nothrow @safe pure @nogc { + import std.conv : emplaceRef; enum n = arr.length; U[n] ret = void; static foreach (i; 0 .. n) @@ -4195,7 +4200,7 @@ void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc } // TODO: add this to assertThrown in std.exception -bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow pure @system +private bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow pure @system { try { From 23fa8a819f781f0cdd5799d613e4fa373cdc94e4 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Mar 2018 15:04:44 -0700 Subject: [PATCH 03/23] merged asStaticCast into asStatic --- std/array.d | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/std/array.d b/std/array.d index f025a729c09..3b4461ba0dc 100644 --- a/std/array.d +++ b/std/array.d @@ -3998,7 +3998,9 @@ Params: arr = The array elements Returns: A static array constructed from `arr`. The type of elements can be specified implicitly (`int[2] a = [1,2].asStatic;`) or explicitly -(`float[2] a = [1,2].asStaticCast!float`). +(`float[2] a = [1,2].asStatic!float`). +The result is an rvalue, therefore uses like +`foo([1, 2, 3].asStatic)` may be inefficient because of the copies. +/ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc { @@ -4006,7 +4008,8 @@ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe } /// ditto -U[n] asStaticCast(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc +U[n] asStatic(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc +if(!is(U==T)) { import std.conv : emplaceRef; U[n] ret = void; @@ -4023,7 +4026,7 @@ nothrow pure @safe unittest auto a = [0, 1].asStatic; assert(is(typeof(a) == int[2]) && a == [0, 1]); - auto b = [0, 1].asStaticCast!byte; + auto b = [0, 1].asStatic!byte; assert(is(typeof(b) == byte[2]) && b == [0, 1]); } @@ -4038,16 +4041,16 @@ nothrow pure @safe unittest [1, 2, val].asStatic.checkStaticArray!int(gold); } - [1, 2, val].asStaticCast!double.checkStaticArray!double(gold); - [1, 2, 3].asStaticCast!int.checkStaticArray!int(gold); + [1, 2, val].asStatic!double.checkStaticArray!double(gold); + [1, 2, 3].asStatic!int.checkStaticArray!int(gold); - [1, 2, 3].asStaticCast!(const(int)).checkStaticArray!(const(int))(gold); - [1, 2, 3].asStaticCast!(const(double)).checkStaticArray!(const(double))(gold); + [1, 2, 3].asStatic!(const(int)).checkStaticArray!(const(int))(gold); + [1, 2, 3].asStatic!(const(double)).checkStaticArray!(const(double))(gold); { const(int)[3] a2 = [1, 2, 3].asStatic; } - [1, 129].asStaticCast!byte.checkStaticArray!byte([1, -127]); + [1, 129].asStatic!byte.checkStaticArray!byte([1, -127]); } @@ -4072,7 +4075,7 @@ auto asStatic(size_t n, T)(T a) nothrow @safe pure @nogc } /// ditto -auto asStaticCast(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc +auto asStatic(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc { import std.conv : emplaceRef; U[n] ret = void; @@ -4092,7 +4095,7 @@ nothrow pure @safe unittest auto a = 2.iota.asStatic!2; assert(is(typeof(a) == int[2]) && a == [0, 1]); - auto b = 2.iota.asStaticCast!(byte[2]); + auto b = 2.iota.asStatic!(byte[2]); assert(is(typeof(b) == byte[2]) && b == [0, 1]); } @@ -4105,8 +4108,8 @@ nothrow pure @safe unittest import std.range : iota; 2.iota.asStatic!2.checkStaticArray!int([0, 1]); - 2.iota.asStaticCast!(double[2]).checkStaticArray!double([0, 1]); - 2.iota.asStaticCast!(byte[2]).checkStaticArray!byte([0, 1]); + 2.iota.asStatic!(double[2]).checkStaticArray!double([0, 1]); + 2.iota.asStatic!(byte[2]).checkStaticArray!byte([0, 1]); } nothrow pure @system unittest @@ -4159,7 +4162,7 @@ auto asStatic(alias arr)() nothrow @safe pure @nogc } /// ditto -auto asStaticCast(U, alias arr)() nothrow @safe pure @nogc +auto asStatic(U, alias arr)() nothrow @safe pure @nogc { import std.conv : emplaceRef; enum n = arr.length; @@ -4179,7 +4182,7 @@ nothrow pure @safe unittest enum a = asStatic!(2.iota); assert(is(typeof(a) == int[2]) && a == [0, 1]); - enum b = asStaticCast!(byte, 2.iota); + enum b = asStatic!(byte, 2.iota); assert(is(typeof(b) == byte[2]) && b == [0, 1]); } @@ -4189,8 +4192,8 @@ nothrow pure @safe unittest enum a = asStatic!(2.iota); asStatic!(2.iota).checkStaticArray!int([0, 1]); - asStaticCast!(double, 2.iota).checkStaticArray!double([0, 1]); - asStaticCast!(byte, 2.iota).checkStaticArray!byte([0, 1]); + asStatic!(double, 2.iota).checkStaticArray!double([0, 1]); + asStatic!(byte, 2.iota).checkStaticArray!byte([0, 1]); } void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc From b36ecb96c366b0ac3c0eb6376fe5959559427d1a Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Mar 2018 15:07:34 -0700 Subject: [PATCH 04/23] removed staticArray,staticArrayCast, redundant with asStatic --- std/array.d | 67 +---------------------------------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/std/array.d b/std/array.d index 3b4461ba0dc..a7a0bb68b67 100644 --- a/std/array.d +++ b/std/array.d @@ -3928,71 +3928,6 @@ unittest assert(appA.data == "hellow"); } -/++ -Params: a = The array elements - -Returns: A static array constructed from `a`. The type of elements can be -specified implicitly (`int[2] a = staticArray(1,2);`) or explicitly -(`float[2] a = staticArray!float(1,2)`). -The result is an rvalue, therefore uses like -`foo(staticArray(1, 2, 3))` may be inefficient because of the copies. -+/ -pragma(inline, true) U[T.length] staticArray(U = CommonType!T, T...)(T a) nothrow @safe pure @nogc -{ - return [a]; -} - -/// ditto -// Workaround https://issues.dlang.org/show_bug.cgi?id=16779 (make alias to staticArray once fixed) -pragma(inline, true) U[T.length] staticArrayCast(U, T...)(T a) nothrow @safe pure @nogc -{ - import std.conv : emplaceRef; - enum n = T.length; - U[n] ret = void; - static foreach (i; 0 .. n) - { - // 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 - emplaceRef!U(ret[i], cast(U) a[i]); - } - return ret; -} - -/// -nothrow pure @safe unittest -{ - auto a = staticArray(1, 2); - assert(is(typeof(a) == int[2]) && a == [1, 2]); - - auto b = staticArrayCast!byte(1, 2); - assert(is(typeof(b) == byte[2]) && b == [1, 2]); -} - -nothrow pure @safe unittest -{ - int val = 3; - staticArray(1, 2, val).checkStaticArray!int([1, 2, 3]); - staticArray(1, 2.0).checkStaticArray!double([1, 2.0]); - assert(!__traits(compiles, staticArray(1, ""))); - staticArray().checkStaticArray!void([]); - staticArray!float(1, 2).checkStaticArray!float([1, 2]); - // auto a = staticArray!byte(1, 2); - staticArrayCast!byte(1, 2).checkStaticArray!byte([1, 2]); - staticArrayCast!byte(1, 129).checkStaticArray!byte([1, -127]); - - staticArrayCast!(const(int))(1, 2).checkStaticArray!(const(int))([1, 2]); - staticArrayCast!(immutable(int))(1, 2).checkStaticArray!(immutable(int))([1, 2]); - staticArray([1]).checkStaticArray!(int[])([[1]]); -} - -@system unittest -{ - version (Bug) - { - // NOTE: correctly issues a deprecation - int[] a2 = staticArray(1, 2); - } -} - /++ Params: arr = The array elements @@ -4009,7 +3944,7 @@ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe /// ditto U[n] asStatic(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc -if(!is(U==T)) +if (!is(U==T)) { import std.conv : emplaceRef; U[n] ret = void; From ce8e5df01f542c07783f6081ea865df37e09117f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Mar 2018 15:32:47 -0700 Subject: [PATCH 05/23] fixup --- std/array.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/array.d b/std/array.d index a7a0bb68b67..cd4d96755c3 100644 --- a/std/array.d +++ b/std/array.d @@ -3944,7 +3944,7 @@ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe /// ditto U[n] asStatic(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc -if (!is(U==T)) +if (!is(U == T)) { import std.conv : emplaceRef; U[n] ret = void; From 3e881b2bf5686b719cbb476749c31e4673f5a233 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 13 Mar 2018 16:02:16 -0700 Subject: [PATCH 06/23] fixup --- std/array.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/array.d b/std/array.d index cd4d96755c3..06d95322f52 100644 --- a/std/array.d +++ b/std/array.d @@ -4131,7 +4131,7 @@ nothrow pure @safe unittest asStatic!(byte, 2.iota).checkStaticArray!byte([0, 1]); } -void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc +private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc { assert(is(T1 == T[T1.length])); assert(a == b); From 01187db3d7fecbd74aa1777f3bdc88f2b633be1b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Mar 2018 15:27:28 -0700 Subject: [PATCH 07/23] address comments; code reuse in some overloads --- std/array.d | 48 ++++++++++++++---------------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/std/array.d b/std/array.d index 06d95322f52..6188e6d6fef 100644 --- a/std/array.d +++ b/std/array.d @@ -3929,28 +3929,27 @@ unittest } /++ -Params: arr = The array elements +Params: a = The input elements -Returns: A static array constructed from `arr`. The type of elements can be +Returns: A static array constructed from `a`. The type of elements can be specified implicitly (`int[2] a = [1,2].asStatic;`) or explicitly (`float[2] a = [1,2].asStatic!float`). -The result is an rvalue, therefore uses like -`foo([1, 2, 3].asStatic)` may be inefficient because of the copies. +Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. +/ -pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc +pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] a) nothrow @safe pure @nogc { - return arr; + return a; } /// ditto -U[n] asStatic(U, T, size_t n)(auto ref T[n] arr) nothrow @safe pure @nogc +U[n] asStatic(U, T, size_t n)(auto ref T[n] a) nothrow @safe pure @nogc if (!is(U == T)) { import std.conv : emplaceRef; U[n] ret = void; static foreach (i; 0 .. n) { - emplaceRef!U(ret[i], cast(U) arr[i]); + emplaceRef!U(ret[i], cast(U) a[i]); } return ret; } @@ -3989,11 +3988,7 @@ nothrow pure @safe unittest } -/++ -Params: a = input range of elements - -Returns: A static array constructed from `a`. -+/ +/// ditto auto asStatic(size_t n, T)(T a) nothrow @safe pure @nogc { import std.conv : emplaceRef; @@ -4079,34 +4074,19 @@ nothrow pure @system unittest } /++ -Params: arr = the compile time range +Params: a = the compile time range -Returns: A static array constructed from `arr`. +Returns: A static array constructed from `a`. +/ -auto asStatic(alias arr)() nothrow @safe pure @nogc +auto asStatic(alias a)() nothrow @safe pure @nogc { - import std.conv : emplaceRef; - enum n = arr.length; - alias U = typeof(arr[0]); - U[n] ret = void; - static foreach (i; 0 .. n) - { - emplaceRef!U(ret[i], arr[i]); - } - return ret; + return .asStatic!(cast(size_t) a.length)(a); } /// ditto -auto asStatic(U, alias arr)() nothrow @safe pure @nogc +auto asStatic(U, alias a)() nothrow @safe pure @nogc { - import std.conv : emplaceRef; - enum n = arr.length; - U[n] ret = void; - static foreach (i; 0 .. n) - { - emplaceRef!U(ret[i], cast(U) arr[i]); - } - return ret; + return .asStatic!(U[cast(size_t) a.length])(a); } /// From 1a4dbc5cfef4447cf3c815a344cee7f8c51a86d2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Mar 2018 15:42:07 -0700 Subject: [PATCH 08/23] improve docs --- std/array.d | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/std/array.d b/std/array.d index 6188e6d6fef..0d254e3f2e6 100644 --- a/std/array.d +++ b/std/array.d @@ -3931,9 +3931,15 @@ unittest /++ Params: a = The input elements -Returns: A static array constructed from `a`. The type of elements can be -specified implicitly (`int[2] a = [1,2].asStatic;`) or explicitly -(`float[2] a = [1,2].asStatic!float`). +Returns: A static array constructed from `a`. + +The type of elements can be specified implicitly (`int[2] a = [1,2].asStatic;`) +or explicitly (`float[2] a = [1,2].asStatic!float`). When `a` is a range, +the number of elements has to be given as template argument (eg `2.iota.asStatic!2`). +Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). +Range `a` can also be specified as a template argument (eg: `asStatic!(2.iota)` +or `asStatic!(double, 2.iota)`. + Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. +/ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] a) nothrow @safe pure @nogc @@ -4073,11 +4079,7 @@ nothrow pure @system unittest } } -/++ -Params: a = the compile time range - -Returns: A static array constructed from `a`. -+/ +/// auto asStatic(alias a)() nothrow @safe pure @nogc { return .asStatic!(cast(size_t) a.length)(a); @@ -4117,7 +4119,7 @@ private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc assert(a == b); } -// TODO: add this to assertThrown in std.exception +// TODO: consider adding this to assertThrown in std.exception private bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow pure @system { try From 2f9fd51dcb3b907fb0041258a6709061543da835 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Mar 2018 15:44:58 -0700 Subject: [PATCH 09/23] unittest: call checkNogc --- std/array.d | 1 + 1 file changed, 1 insertion(+) diff --git a/std/array.d b/std/array.d index 0d254e3f2e6..1de72c43ecd 100644 --- a/std/array.d +++ b/std/array.d @@ -3980,6 +3980,7 @@ nothrow pure @safe unittest { [1, 2, val].asStatic.checkStaticArray!int(gold); } + checkNogc(); [1, 2, val].asStatic!double.checkStaticArray!double(gold); [1, 2, 3].asStatic!int.checkStaticArray!int(gold); From b9d44edb1e81f1e9cbb53b4d66375f35794db157 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Mar 2018 15:48:52 -0700 Subject: [PATCH 10/23] doc fixup --- std/array.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/array.d b/std/array.d index 1de72c43ecd..9e60bc517c2 100644 --- a/std/array.d +++ b/std/array.d @@ -3938,7 +3938,7 @@ or explicitly (`float[2] a = [1,2].asStatic!float`). When `a` is a range, the number of elements has to be given as template argument (eg `2.iota.asStatic!2`). Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). Range `a` can also be specified as a template argument (eg: `asStatic!(2.iota)` -or `asStatic!(double, 2.iota)`. +or `asStatic!(double, 2.iota)`). Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. +/ From fc54fe5368e7ef3926cab4a2cec110322934cb5b Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 14 Mar 2018 23:54:18 -0700 Subject: [PATCH 11/23] address comments --- std/array.d | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/std/array.d b/std/array.d index 9e60bc517c2..1dff1788ba5 100644 --- a/std/array.d +++ b/std/array.d @@ -3929,18 +3929,19 @@ unittest } /++ -Params: a = The input elements - -Returns: A static array constructed from `a`. - -The type of elements can be specified implicitly (`int[2] a = [1,2].asStatic;`) -or explicitly (`float[2] a = [1,2].asStatic!float`). When `a` is a range, +Constructs a static array from `a`. +The type of elements can be specified implicitly (`auto a = [1,2].asStatic;` of type int[2]) +or explicitly (`auto a = [1,2].asStatic!float` of type float[2]). When `a` is a range, the number of elements has to be given as template argument (eg `2.iota.asStatic!2`). Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). Range `a` can also be specified as a template argument (eg: `asStatic!(2.iota)` or `asStatic!(double, 2.iota)`). Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. + +Params: a = The input elements + +Returns: A static array constructed from `a`. +/ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] a) nothrow @safe pure @nogc { @@ -3960,7 +3961,7 @@ if (!is(U == T)) return ret; } -/// +/// static array from array nothrow pure @safe unittest { auto a = [0, 1].asStatic; @@ -4025,14 +4026,14 @@ auto asStatic(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc return ret; } -/// +/// static array from range + size nothrow pure @safe unittest { import std.range : iota; - - auto a = 2.iota.asStatic!2; + auto input = 2.iota; + auto a = input.asStatic!2; assert(is(typeof(a) == int[2]) && a == [0, 1]); - auto b = 2.iota.asStatic!(byte[2]); + auto b = input.asStatic!(byte[2]); assert(is(typeof(b) == byte[2]) && b == [0, 1]); } @@ -4080,7 +4081,7 @@ nothrow pure @system unittest } } -/// +/// ditto auto asStatic(alias a)() nothrow @safe pure @nogc { return .asStatic!(cast(size_t) a.length)(a); @@ -4092,7 +4093,7 @@ auto asStatic(U, alias a)() nothrow @safe pure @nogc return .asStatic!(U[cast(size_t) a.length])(a); } -/// +/// static array from CT range nothrow pure @safe unittest { import std.range : iota; @@ -4116,7 +4117,7 @@ nothrow pure @safe unittest private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc { - assert(is(T1 == T[T1.length])); + static assert(is(T1 == T[T1.length])); assert(a == b); } From 005096822736b9884e23c6943e04cb246936fce5 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 15 Mar 2018 00:09:05 -0700 Subject: [PATCH 12/23] removed some attributes from templated functions --- std/array.d | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/std/array.d b/std/array.d index 1dff1788ba5..dbb453208d4 100644 --- a/std/array.d +++ b/std/array.d @@ -3949,7 +3949,7 @@ pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] a) nothrow @safe p } /// ditto -U[n] asStatic(U, T, size_t n)(auto ref T[n] a) nothrow @safe pure @nogc +U[n] asStatic(U, T, size_t n)(auto ref T[n] a) if (!is(U == T)) { import std.conv : emplaceRef; @@ -3997,7 +3997,7 @@ nothrow pure @safe unittest } /// ditto -auto asStatic(size_t n, T)(T a) nothrow @safe pure @nogc +auto asStatic(size_t n, T)(T a) { import std.conv : emplaceRef; // TODO: ElementType vs ForeachType @@ -4082,13 +4082,13 @@ nothrow pure @system unittest } /// ditto -auto asStatic(alias a)() nothrow @safe pure @nogc +auto asStatic(alias a)() { return .asStatic!(cast(size_t) a.length)(a); } /// ditto -auto asStatic(U, alias a)() nothrow @safe pure @nogc +auto asStatic(U, alias a)() { return .asStatic!(U[cast(size_t) a.length])(a); } @@ -4122,7 +4122,7 @@ private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc } // TODO: consider adding this to assertThrown in std.exception -private bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow pure @system +private bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow { try { From a965ed79d8a32c78a13edcbab1d4e7ed664a4ecc Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 15 Mar 2018 00:17:14 -0700 Subject: [PATCH 13/23] address comment assert => static assert --- std/array.d | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/std/array.d b/std/array.d index dbb453208d4..d38c191efef 100644 --- a/std/array.d +++ b/std/array.d @@ -3965,10 +3965,12 @@ if (!is(U == T)) nothrow pure @safe unittest { auto a = [0, 1].asStatic; - assert(is(typeof(a) == int[2]) && a == [0, 1]); + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); auto b = [0, 1].asStatic!byte; - assert(is(typeof(b) == byte[2]) && b == [0, 1]); + static assert(is(typeof(b) == byte[2])); + assert(b == [0, 1]); } nothrow pure @safe unittest @@ -4032,9 +4034,11 @@ nothrow pure @safe unittest import std.range : iota; auto input = 2.iota; auto a = input.asStatic!2; - assert(is(typeof(a) == int[2]) && a == [0, 1]); + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); auto b = input.asStatic!(byte[2]); - assert(is(typeof(b) == byte[2]) && b == [0, 1]); + static assert(is(typeof(b) == byte[2])); + assert(b == [0, 1]); } nothrow pure @safe unittest @@ -4099,10 +4103,12 @@ nothrow pure @safe unittest import std.range : iota; enum a = asStatic!(2.iota); - assert(is(typeof(a) == int[2]) && a == [0, 1]); + static assert(is(typeof(a) == int[2])); + assert(a == [0, 1]); enum b = asStatic!(byte, 2.iota); - assert(is(typeof(b) == byte[2]) && b == [0, 1]); + static assert(is(typeof(b) == byte[2])); + assert(b == [0, 1]); } nothrow pure @safe unittest From 6519a2eae8515e4fab3d48c1cbaf4918ace0c8e2 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 15 Mar 2018 00:35:00 -0700 Subject: [PATCH 14/23] add changelog/std-array-asStatic.md --- changelog/std-array-asStatic.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 changelog/std-array-asStatic.md diff --git a/changelog/std-array-asStatic.md b/changelog/std-array-asStatic.md new file mode 100644 index 00000000000..912427af47c --- /dev/null +++ b/changelog/std-array-asStatic.md @@ -0,0 +1,27 @@ +Added `asStatic` to construct a static array from input array / range / CT range. + +The type of elements can be specified implicitly (`auto a = [1,2].asStatic;` of type int[2]) +or explicitly (`auto a = [1,2].asStatic!float` of type float[2]). When `a` is a range, +the number of elements has to be given as template argument (eg `2.iota.asStatic!2`). +Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). +Range `a` can also be specified as a template argument (eg: `asStatic!(2.iota)` +or `asStatic!(double, 2.iota)`). + +Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. + +--- +auto a1 = [0, 1].asStatic; +static assert(is(typeof(a1) == int[2])); +assert(a1 == [0, 1]); + +auto a2 = [0, 1].asStatic!byte; +static assert(is(typeof(a2) == byte[2])); + +import std.range : iota; +auto input = 2.iota; +auto a3 = input.asStatic!2; +auto a4 = input.asStatic!(byte[2]); + +auto a5 = asStatic!(2.iota); +auto a6 = asStatic!(double, 2.iota); +--- From 3cd479b5aa78c1eebc97aa828629601151aa1084 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 15 Mar 2018 01:35:54 -0700 Subject: [PATCH 15/23] address comments --- changelog/std-array-asStatic.md | 12 +++++++----- std/array.d | 14 ++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/changelog/std-array-asStatic.md b/changelog/std-array-asStatic.md index 912427af47c..678e4ba32ec 100644 --- a/changelog/std-array-asStatic.md +++ b/changelog/std-array-asStatic.md @@ -1,11 +1,13 @@ Added `asStatic` to construct a static array from input array / range / CT range. -The type of elements can be specified implicitly (`auto a = [1,2].asStatic;` of type int[2]) -or explicitly (`auto a = [1,2].asStatic!float` of type float[2]). When `a` is a range, -the number of elements has to be given as template argument (eg `2.iota.asStatic!2`). +The type of elements can be specified implicitly (`[1,2].asStatic` of type int[2]) +or explicitly (`[1,2].asStatic!float` of type float[2]). +When `a` is a range (not known at compile time), the number of elements has to be given as template argument +(eg `myrange.asStatic!2`). Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). -Range `a` can also be specified as a template argument (eg: `asStatic!(2.iota)` -or `asStatic!(double, 2.iota)`). +When the range `a` is known at compile time, it can also be specified as a +template argument to avoid having to specify the number of elements +(eg: `asStatic!(2.iota)` or `asStatic!(double, 2.iota)`). Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. diff --git a/std/array.d b/std/array.d index d38c191efef..5b8913c2c3f 100644 --- a/std/array.d +++ b/std/array.d @@ -3930,12 +3930,14 @@ unittest /++ Constructs a static array from `a`. -The type of elements can be specified implicitly (`auto a = [1,2].asStatic;` of type int[2]) -or explicitly (`auto a = [1,2].asStatic!float` of type float[2]). When `a` is a range, -the number of elements has to be given as template argument (eg `2.iota.asStatic!2`). +The type of elements can be specified implicitly (`[1,2].asStatic` of type int[2]) +or explicitly (`[1,2].asStatic!float` of type float[2]). +When `a` is a range (not known at compile time), the number of elements has to be given as template argument +(eg `myrange.asStatic!2`). Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). -Range `a` can also be specified as a template argument (eg: `asStatic!(2.iota)` -or `asStatic!(double, 2.iota)`). +When the range `a` is known at compile time, it can also be specified as a +template argument to avoid having to specify the number of elements +(eg: `asStatic!(2.iota)` or `asStatic!(double, 2.iota)`). Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. @@ -4128,7 +4130,7 @@ private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc } // TODO: consider adding this to assertThrown in std.exception -private bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow +version(unittest) private bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow { try { From aa082d46f7b6bcd0f6a40e46d75443314dae026c Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 15 Mar 2018 02:04:30 -0700 Subject: [PATCH 16/23] address comments --- std/array.d | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/std/array.d b/std/array.d index 5b8913c2c3f..03942ab27be 100644 --- a/std/array.d +++ b/std/array.d @@ -4062,29 +4062,9 @@ nothrow pure @system unittest assert(isThrown!Error(2.iota.asStatic!1)); assert(isThrown!Error(2.iota.asStatic!3)); - // NOTE: alternatives are not nothrow: - version (none) - { - import std.exception : assertThrown; - - assertThrown!Error(2.iota.asStatic!3); - import std.exception : ifThrown; - - assert(ifThrown!Error({ 2.iota.asStatic!1; return false; }(), true)); - } -} - -@system unittest -{ - version (Bug) - { - // https://issues.dlang.org/show_bug.cgi?id=16779 - auto a2 = [1, 2, 3].asStatic!byte; - auto a3 = [1, 2, 3].asStatic!ubyte; - // NOTE: correctly issues a deprecation - int[] a2 = [1, 2].asStatic; - } + // NOTE: correctly issues a deprecation + // int[] a2 = [1, 2].asStatic; } /// ditto @@ -4129,7 +4109,20 @@ private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc assert(a == b); } -// TODO: consider adding this to assertThrown in std.exception +/+ +TODO: consider adding this to assertThrown in std.exception +The alternatives are not nothrow (see https://issues.dlang.org/show_bug.cgi?id=12647) +--- +import std.exception : assertThrown; +assertThrown!Error(expr_that_throws); + +// or +import std.exception : ifThrown; +scope(failure) assert(0); +assert(ifThrown!Error({ expr_that_throws; return false; }(), true)); +--- +Also, `isThrown` is easier to use than ifThrown and more flexible than assertThrown. ++/ version(unittest) private bool isThrown(T : Throwable = Exception, E)(lazy E expression) nothrow { try From 25114ab3fc82c5a43bba7fb21fa37ba0ce4ccf87 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 15 Mar 2018 11:49:51 -0700 Subject: [PATCH 17/23] checkStaticArray=>version(unittest) --- std/array.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/array.d b/std/array.d index 03942ab27be..554a7642442 100644 --- a/std/array.d +++ b/std/array.d @@ -4103,7 +4103,7 @@ nothrow pure @safe unittest asStatic!(byte, 2.iota).checkStaticArray!byte([0, 1]); } -private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc +version(unittest) private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc { static assert(is(T1 == T[T1.length])); assert(a == b); From 5e318a888418c0e1e64627ecc5877861b4ce2371 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Mar 2018 15:40:02 -0700 Subject: [PATCH 18/23] address comments including s/asStatic/staticArray --- std/array.d | 81 +++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/std/array.d b/std/array.d index 554a7642442..235f309a3f9 100644 --- a/std/array.d +++ b/std/array.d @@ -3930,28 +3930,29 @@ unittest /++ Constructs a static array from `a`. -The type of elements can be specified implicitly (`[1,2].asStatic` of type int[2]) -or explicitly (`[1,2].asStatic!float` of type float[2]). +The type of elements can be specified implicitly (`[1,2].staticArray` of type int[2]) +or explicitly (`[1,2].staticArray!float` of type float[2]). When `a` is a range (not known at compile time), the number of elements has to be given as template argument -(eg `myrange.asStatic!2`). -Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). +(eg `myrange.staticArray!2`). +Size and type can be combined (eg: `2.iota.staticArray!(byte[2])`). When the range `a` is known at compile time, it can also be specified as a template argument to avoid having to specify the number of elements -(eg: `asStatic!(2.iota)` or `asStatic!(double, 2.iota)`). +(eg: `staticArray!(2.iota)` or `staticArray!(double, 2.iota)`). -Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. +Note: `staticArray` returns by value, so expressions involving large arrays may be inefficient. Params: a = The input elements Returns: A static array constructed from `a`. +/ -pragma(inline, true) T[n] asStatic(T, size_t n)(auto ref T[n] a) nothrow @safe pure @nogc + +pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) nothrow @safe pure @nogc { return a; } /// ditto -U[n] asStatic(U, T, size_t n)(auto ref T[n] a) +U[n] staticArray(U, T, size_t n)(auto ref T[n] a) if (!is(U == T)) { import std.conv : emplaceRef; @@ -3966,11 +3967,11 @@ if (!is(U == T)) /// static array from array nothrow pure @safe unittest { - auto a = [0, 1].asStatic; + auto a = [0, 1].staticArray; static assert(is(typeof(a) == int[2])); assert(a == [0, 1]); - auto b = [0, 1].asStatic!byte; + auto b = [0, 1].staticArray!byte; static assert(is(typeof(b) == byte[2])); assert(b == [0, 1]); } @@ -3979,29 +3980,29 @@ nothrow pure @safe unittest { int val = 3; static immutable gold = [1, 2, 3]; - [1, 2, val].asStatic.checkStaticArray!int([1, 2, 3]); + [1, 2, val].staticArray.checkStaticArray!int([1, 2, 3]); @nogc void checkNogc() { - [1, 2, val].asStatic.checkStaticArray!int(gold); + [1, 2, val].staticArray.checkStaticArray!int(gold); } checkNogc(); - [1, 2, val].asStatic!double.checkStaticArray!double(gold); - [1, 2, 3].asStatic!int.checkStaticArray!int(gold); + [1, 2, val].staticArray!double.checkStaticArray!double(gold); + [1, 2, 3].staticArray!int.checkStaticArray!int(gold); - [1, 2, 3].asStatic!(const(int)).checkStaticArray!(const(int))(gold); - [1, 2, 3].asStatic!(const(double)).checkStaticArray!(const(double))(gold); + [1, 2, 3].staticArray!(const(int)).checkStaticArray!(const(int))(gold); + [1, 2, 3].staticArray!(const(double)).checkStaticArray!(const(double))(gold); { - const(int)[3] a2 = [1, 2, 3].asStatic; + const(int)[3] a2 = [1, 2, 3].staticArray; } - [1, 129].asStatic!byte.checkStaticArray!byte([1, -127]); + [1, 129].staticArray!byte.checkStaticArray!byte([1, -127]); } /// ditto -auto asStatic(size_t n, T)(T a) +auto staticArray(size_t n, T)(T a) { import std.conv : emplaceRef; // TODO: ElementType vs ForeachType @@ -4017,7 +4018,7 @@ auto asStatic(size_t n, T)(T a) } /// ditto -auto asStatic(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc +auto staticArray(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc { import std.conv : emplaceRef; U[n] ret = void; @@ -4035,10 +4036,10 @@ nothrow pure @safe unittest { import std.range : iota; auto input = 2.iota; - auto a = input.asStatic!2; + auto a = input.staticArray!2; static assert(is(typeof(a) == int[2])); assert(a == [0, 1]); - auto b = input.asStatic!(byte[2]); + auto b = input.staticArray!(byte[2]); static assert(is(typeof(b) == byte[2])); assert(b == [0, 1]); } @@ -4046,37 +4047,39 @@ nothrow pure @safe unittest nothrow pure @safe unittest { - auto a = [1, 2].asStatic; + auto a = [1, 2].staticArray; assert(is(typeof(a) == int[2]) && a == [1, 2]); import std.range : iota; - 2.iota.asStatic!2.checkStaticArray!int([0, 1]); - 2.iota.asStatic!(double[2]).checkStaticArray!double([0, 1]); - 2.iota.asStatic!(byte[2]).checkStaticArray!byte([0, 1]); + 2.iota.staticArray!2.checkStaticArray!int([0, 1]); + 2.iota.staticArray!(double[2]).checkStaticArray!double([0, 1]); + 2.iota.staticArray!(byte[2]).checkStaticArray!byte([0, 1]); } nothrow pure @system unittest { import std.range : iota; - assert(isThrown!Error(2.iota.asStatic!1)); - assert(isThrown!Error(2.iota.asStatic!3)); + assert(isThrown!Error(2.iota.staticArray!1)); + assert(isThrown!Error(2.iota.staticArray!3)); // NOTE: correctly issues a deprecation - // int[] a2 = [1, 2].asStatic; + // int[] a2 = [1, 2].staticArray; } /// ditto -auto asStatic(alias a)() +auto staticArray(alias a)() { - return .asStatic!(cast(size_t) a.length)(a); + // NOTE: without `cast`, getting error: + // cannot deduce function from argument types !(length)(Result) + return .staticArray!(cast(size_t) a.length)(a); } /// ditto -auto asStatic(U, alias a)() +auto staticArray(U, alias a)() { - return .asStatic!(U[cast(size_t) a.length])(a); + return .staticArray!(U[cast(size_t) a.length])(a); } /// static array from CT range @@ -4084,11 +4087,11 @@ nothrow pure @safe unittest { import std.range : iota; - enum a = asStatic!(2.iota); + enum a = staticArray!(2.iota); static assert(is(typeof(a) == int[2])); assert(a == [0, 1]); - enum b = asStatic!(byte, 2.iota); + enum b = staticArray!(byte, 2.iota); static assert(is(typeof(b) == byte[2])); assert(b == [0, 1]); } @@ -4097,10 +4100,10 @@ nothrow pure @safe unittest { import std.range : iota; - enum a = asStatic!(2.iota); - asStatic!(2.iota).checkStaticArray!int([0, 1]); - asStatic!(double, 2.iota).checkStaticArray!double([0, 1]); - asStatic!(byte, 2.iota).checkStaticArray!byte([0, 1]); + enum a = staticArray!(2.iota); + staticArray!(2.iota).checkStaticArray!int([0, 1]); + staticArray!(double, 2.iota).checkStaticArray!double([0, 1]); + staticArray!(byte, 2.iota).checkStaticArray!byte([0, 1]); } version(unittest) private void checkStaticArray(T, T1, T2)(T1 a, T2 b) nothrow @safe pure @nogc From c19751a95b0bc172a3c7f2abee7420504afa59d7 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Mar 2018 15:50:31 -0700 Subject: [PATCH 19/23] address comments: template constraints --- std/array.d | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/std/array.d b/std/array.d index 235f309a3f9..f96d3e5f68f 100644 --- a/std/array.d +++ b/std/array.d @@ -3956,6 +3956,7 @@ U[n] staticArray(U, T, size_t n)(auto ref T[n] a) if (!is(U == T)) { import std.conv : emplaceRef; + U[n] ret = void; static foreach (i; 0 .. n) { @@ -3986,6 +3987,7 @@ nothrow pure @safe unittest { [1, 2, val].staticArray.checkStaticArray!int(gold); } + checkNogc(); [1, 2, val].staticArray!double.checkStaticArray!double(gold); @@ -4003,10 +4005,12 @@ nothrow pure @safe unittest /// ditto auto staticArray(size_t n, T)(T a) +if (isInputRange!T) { import std.conv : emplaceRef; + // TODO: ElementType vs ForeachType - alias U = typeof(a[0]); + alias U = typeof(a.front); U[n] ret = void; size_t i; foreach (ref ai; a) @@ -4019,8 +4023,10 @@ auto staticArray(size_t n, T)(T a) /// ditto auto staticArray(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc +if (isInputRange!T) { import std.conv : emplaceRef; + U[n] ret = void; size_t i; foreach (ref ai; a) @@ -4035,6 +4041,7 @@ auto staticArray(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc nothrow pure @safe unittest { import std.range : iota; + auto input = 2.iota; auto a = input.staticArray!2; static assert(is(typeof(a) == int[2])); @@ -4070,6 +4077,7 @@ nothrow pure @system unittest /// ditto auto staticArray(alias a)() +if (isInputRange!(typeof(a))) { // NOTE: without `cast`, getting error: // cannot deduce function from argument types !(length)(Result) @@ -4078,6 +4086,7 @@ auto staticArray(alias a)() /// ditto auto staticArray(U, alias a)() +if (isInputRange!(typeof(a))) { return .staticArray!(U[cast(size_t) a.length])(a); } From d7444e700beb9581950f2a817340e9089e756623 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Mar 2018 17:22:21 -0700 Subject: [PATCH 20/23] refactor --- std/array.d | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/std/array.d b/std/array.d index f96d3e5f68f..e4fd5e713fa 100644 --- a/std/array.d +++ b/std/array.d @@ -3958,6 +3958,7 @@ if (!is(U == T)) import std.conv : emplaceRef; U[n] ret = void; + // TODO: ElementType vs ForeachType static foreach (i; 0 .. n) { emplaceRef!U(ret[i], cast(U) a[i]); @@ -4007,18 +4008,8 @@ nothrow pure @safe unittest auto staticArray(size_t n, T)(T a) if (isInputRange!T) { - import std.conv : emplaceRef; - - // TODO: ElementType vs ForeachType - alias U = typeof(a.front); - U[n] ret = void; - size_t i; - foreach (ref ai; a) - { - emplaceRef!U(ret[i++], ai); - } - assert(i == n); - return ret; + alias U = ElementType!T; + return staticArray!(U[n], U, n)(a); } /// ditto From 1066a2fa4eded8ada49dced6c0691014478cc544 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Wed, 21 Mar 2018 17:38:47 -0700 Subject: [PATCH 21/23] make some overloads nothrow to not have to deal with ctors that throw until a better solution is found --- std/array.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/array.d b/std/array.d index e4fd5e713fa..d281caf36a2 100644 --- a/std/array.d +++ b/std/array.d @@ -3952,7 +3952,7 @@ pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a) nothrow @saf } /// ditto -U[n] staticArray(U, T, size_t n)(auto ref T[n] a) +U[n] staticArray(U, T, size_t n)(auto ref T[n] a) nothrow if (!is(U == T)) { import std.conv : emplaceRef; @@ -4013,7 +4013,7 @@ if (isInputRange!T) } /// ditto -auto staticArray(Un : U[n], U, size_t n, T)(T a) nothrow @safe pure @nogc +auto staticArray(Un : U[n], U, size_t n, T)(T a) nothrow if (isInputRange!T) { import std.conv : emplaceRef; From dbc94b0355cc04951c6a476c5923c6a59ad5a200 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Fri, 30 Mar 2018 10:43:51 -0400 Subject: [PATCH 22/23] s/asStatic/staticArray/g --- changelog/std-array-asStatic.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/changelog/std-array-asStatic.md b/changelog/std-array-asStatic.md index 678e4ba32ec..841ecf54e38 100644 --- a/changelog/std-array-asStatic.md +++ b/changelog/std-array-asStatic.md @@ -1,29 +1,29 @@ -Added `asStatic` to construct a static array from input array / range / CT range. +Added `staticArray` to construct a static array from input array / range / CT range. -The type of elements can be specified implicitly (`[1,2].asStatic` of type int[2]) -or explicitly (`[1,2].asStatic!float` of type float[2]). +The type of elements can be specified implicitly (`[1,2].staticArray` of type int[2]) +or explicitly (`[1,2].staticArray!float` of type float[2]). When `a` is a range (not known at compile time), the number of elements has to be given as template argument -(eg `myrange.asStatic!2`). -Size and type can be combined (eg: `2.iota.asStatic!(byte[2])`). +(eg `myrange.staticArray!2`). +Size and type can be combined (eg: `2.iota.staticArray!(byte[2])`). When the range `a` is known at compile time, it can also be specified as a template argument to avoid having to specify the number of elements -(eg: `asStatic!(2.iota)` or `asStatic!(double, 2.iota)`). +(eg: `staticArray!(2.iota)` or `staticArray!(double, 2.iota)`). -Note: `foo([1, 2, 3].asStatic)` may be inefficient because of the copies involved. +Note: `foo([1, 2, 3].staticArray)` may be inefficient because of the copies involved. --- -auto a1 = [0, 1].asStatic; +auto a1 = [0, 1].staticArray; static assert(is(typeof(a1) == int[2])); assert(a1 == [0, 1]); -auto a2 = [0, 1].asStatic!byte; +auto a2 = [0, 1].staticArray!byte; static assert(is(typeof(a2) == byte[2])); import std.range : iota; auto input = 2.iota; -auto a3 = input.asStatic!2; -auto a4 = input.asStatic!(byte[2]); +auto a3 = input.staticArray!2; +auto a4 = input.staticArray!(byte[2]); -auto a5 = asStatic!(2.iota); -auto a6 = asStatic!(double, 2.iota); +auto a5 = staticArray!(2.iota); +auto a6 = staticArray!(double, 2.iota); --- From 60d6cd6a76e3165829532fcb2706f49ebc90cee6 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Fri, 30 Mar 2018 10:56:12 -0400 Subject: [PATCH 23/23] typo --- std/array.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/array.d b/std/array.d index d281caf36a2..d5229d9e26e 100644 --- a/std/array.d +++ b/std/array.d @@ -3933,7 +3933,7 @@ Constructs a static array from `a`. The type of elements can be specified implicitly (`[1,2].staticArray` of type int[2]) or explicitly (`[1,2].staticArray!float` of type float[2]). When `a` is a range (not known at compile time), the number of elements has to be given as template argument -(eg `myrange.staticArray!2`). +(e.g. `myrange.staticArray!2`). Size and type can be combined (eg: `2.iota.staticArray!(byte[2])`). When the range `a` is known at compile time, it can also be specified as a template argument to avoid having to specify the number of elements