Skip to content

Fix Issue 16745 - Add template helper for creating static arrays with the size inferred #4936

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
94 changes: 94 additions & 0 deletions std/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ $(TR $(TH Function Name) $(TH Description)
$(TR $(TD $(LREF split))
$(TD Eagerly split a range or string into an _array.
))
$(TR $(TD $(LREF staticArray))
$(TD Create a static array from a range.
))
$(TR $(TD $(LREF uninitializedArray))
$(TD Returns a new _array of type $(D T) without initializing its elements.
))
Expand Down Expand Up @@ -354,6 +357,97 @@ if (isNarrowString!String)
)));
}


/**
* Return a static array filled with elements from a range.
*
* Params:
* range = a range (or aggregate with $(D opApply) function) whose elements are copied into the static array
* Returns:
* initialized static array
*/
auto staticArray(alias range)()
if (isIterable!(typeof(range)) && !isInfinite!(typeof(range)))
{
import std.array : array;
enum arr = array(range);
enum sA = .staticArray(arr);
return sA;
}

///
@safe @nogc nothrow unittest
{
import std.range;
enum r = iota(3);
auto sa4 = staticArray!r;
static assert(sa4.length == 3);
assert(sa4 == [0, 1, 2]);
}
Copy link
Member

Choose a reason for hiding this comment

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

This strikes me as an obscure feature, and the example doesn't add confidence in the usefulness of the approach. I'd think a CTFE range evaluation should work, i.e. the example above should spell like:

auto sa4 = iota(3).staticArray;
assert(is(typeof(sa4) == int[3]));
assert(sa4 == [0, 1, 2]);

Copy link
Member

Choose a reason for hiding this comment

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


/**
* Returns a static array filled with elements copied from a dynamic array.
* In contrast to the overload that takes its source as a template alias, this takes
* a it as a normal argument. This allows it to be used with runtime arrays in
* situations where the length of the array is guaranteed in the function call expression
* (see examples for details).
*
* Optionally, a target type can be provided as the first template argument, which will result
* in a static array with that element type.
*/
T[N] staticArray(size_t N, T)(T[N] a)
Copy link
Member

Choose a reason for hiding this comment

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

perhaps you could add auto ref to the parameter

{
return a;
}

/// ditto
TargetElemT[N] staticArray(TargetElemT, size_t N, T)(T[N] a)
{
Copy link
Member

Choose a reason for hiding this comment

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

add constraint if (is(T : TargetElemT))

Copy link
Member

Choose a reason for hiding this comment

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

and possibly auto ref to the parameter

Unqual!(TargetElemT)[N] result = void;

import std.conv : emplaceRef;
foreach (i; 0 .. N)
emplaceRef!TargetElemT(result[i], a[i]);
Copy link
Member

Choose a reason for hiding this comment

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

If any of these throws, the destructors of the already-constructed elements is not called.


return (() @trusted => cast(TargetElemT[N])result)();
Copy link
Member

Choose a reason for hiding this comment

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

I'm not clear why this should be always trusted.

}

///
@safe nothrow unittest
{
auto sa = staticArray([1, 2]);
Copy link
Member

Choose a reason for hiding this comment

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

Examples should use the preferred notation [1, 2].staticArray.

static assert(sa.length == 2);
assert(sa == [1, 2]);

auto sa1 = staticArray!(immutable long)(sa[0 .. 1]);
static assert(is(typeof(sa1) == immutable(long)[1]));
assert(sa1 == [1]);

int[] a = [4, 2, 3];
auto sa2 = staticArray(a[0 .. 2]);
static assert(sa2.length == 2);
a[0] = 1;
assert(sa2 == [4, 2]);

const size_t i = 2;
auto sa3 = staticArray(a[0 .. i]);
static assert(sa3.length == 2);
assert(sa3 == [1, 2]);

version(none)
auto sa4 = staticArray(a[]); // not possible
}

///
@nogc @safe nothrow unittest
{
int[3] a = [1, 2, 3];
auto da = a[];
auto sa = staticArray!(const int)(da[0 .. 3]);
static assert(is(typeof(sa) == const(int)[3]));
assert(sa == a);
}

/**
Returns a newly allocated associative _array from a range of key/value tuples.

Expand Down