mirror of
https://github.com/dlang/phobos.git
synced 2025-05-10 22:18:03 +03:00
Merge pull request #1009 from monarchdodra/initializeAll
improvements to uninitializedFill && initializeAll
This commit is contained in:
commit
6996f434af
1 changed files with 110 additions and 58 deletions
170
std/algorithm.d
170
std/algorithm.d
|
@ -1070,6 +1070,9 @@ contain meaningful content. This is of interest for structs that
|
||||||
define copy constructors (for all other types, fill and
|
define copy constructors (for all other types, fill and
|
||||||
uninitializedFill are equivalent).
|
uninitializedFill are equivalent).
|
||||||
|
|
||||||
|
uninitializedFill will only operate on ranges that expose references to its
|
||||||
|
members and have assignable elements.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
struct S { ... }
|
struct S { ... }
|
||||||
|
@ -1079,41 +1082,24 @@ assert(s == [ 42, 42, 42, 42, 42 ]);
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
void uninitializedFill(Range, Value)(Range range, Value filler)
|
void uninitializedFill(Range, Value)(Range range, Value filler)
|
||||||
if (isForwardRange!Range && is(typeof(range.front = filler)))
|
if (isInputRange!Range && hasLvalueElements!Range && is(typeof(range.front = filler)))
|
||||||
{
|
{
|
||||||
alias ElementType!Range T;
|
alias ElementType!Range T;
|
||||||
static if (hasElaborateCopyConstructor!T)
|
static if (hasElaborateAssign!T)
|
||||||
{
|
|
||||||
// Must construct stuff by the book
|
// Must construct stuff by the book
|
||||||
for (; !range.empty; range.popFront())
|
for (; !range.empty; range.popFront())
|
||||||
{
|
emplace(&range.front(), filler);
|
||||||
emplace(&range.front, filler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// Doesn't matter whether fill is initialized or not
|
// Doesn't matter whether fill is initialized or not
|
||||||
return fill(range, filler);
|
return fill(range, filler);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
deprecated("Cannot reliably call uninitializedFill on range that does not expose references. Use fill instead.")
|
||||||
|
void uninitializedFill(Range, Value)(Range range, Value filler)
|
||||||
|
if (isInputRange!Range && !hasLvalueElements!Range && is(typeof(range.front = filler)))
|
||||||
{
|
{
|
||||||
debug(std_algorithm) scope(success)
|
static assert(hasElaborateAssign!T, "Cannot execute uninitializedFill a range that does not expose references, and whose objects have an elaborate assign.");
|
||||||
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
return fill(range, filler);
|
||||||
int[] a = [ 1, 2, 3 ];
|
|
||||||
uninitializedFill(a, 6);
|
|
||||||
assert(a == [ 6, 6, 6 ]);
|
|
||||||
void fun0()
|
|
||||||
{
|
|
||||||
foreach (i; 0 .. 1000)
|
|
||||||
{
|
|
||||||
foreach (ref e; a) e = 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void fun1() { foreach (i; 0 .. 1000) fill(a, 6); }
|
|
||||||
//void fun2() { foreach (i; 0 .. 1000) fill2(a, 6); }
|
|
||||||
//writeln(benchmark!(fun0, fun1, fun2)(10000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1121,6 +1107,9 @@ Initializes all elements of a range with their $(D .init)
|
||||||
value. Assumes that the range does not currently contain meaningful
|
value. Assumes that the range does not currently contain meaningful
|
||||||
content.
|
content.
|
||||||
|
|
||||||
|
initializeAll will operate on ranges that expose references to its
|
||||||
|
members and have assignable elements, as well as on (mutable) strings.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
struct S { ... }
|
struct S { ... }
|
||||||
|
@ -1130,56 +1119,119 @@ assert(s == [ 0, 0, 0, 0, 0 ]);
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
void initializeAll(Range)(Range range)
|
void initializeAll(Range)(Range range)
|
||||||
if (isForwardRange!Range && is(typeof(range.front = range.front)))
|
if (isInputRange!Range && hasLvalueElements!Range && hasAssignableElements!Range)
|
||||||
{
|
{
|
||||||
alias ElementType!Range T;
|
alias ElementType!Range T;
|
||||||
static assert(is(typeof(&(range.front()))) || !hasElaborateAssign!T,
|
static if (hasElaborateAssign!T)
|
||||||
"Cannot initialize a range that does not expose"
|
|
||||||
" references to its elements");
|
|
||||||
static if (!isDynamicArray!Range)
|
|
||||||
{
|
{
|
||||||
static if (is(typeof(&(range.front()))))
|
//Elaborate opAssign. Must go the memcpy road.
|
||||||
{
|
//We avoid calling emplace here, because our goal is to initialize to
|
||||||
// Range exposes references
|
//the static state of T.init,
|
||||||
for (; !range.empty; range.popFront())
|
//So we want to avoid any un-necassarilly CC'ing of T.init
|
||||||
{
|
auto p = typeid(T).init().ptr;
|
||||||
memcpy(&(range.front()), &T.init, T.sizeof);
|
if (p)
|
||||||
}
|
for ( ; !range.empty ; range.popFront() )
|
||||||
|
memcpy(&range.front(), p, T.sizeof);
|
||||||
|
else
|
||||||
|
static if (isDynamicArray!Range)
|
||||||
|
memset(range.ptr, 0, range.length * T.sizeof);
|
||||||
|
else
|
||||||
|
for ( ; !range.empty ; range.popFront() )
|
||||||
|
memset(&range.front(), 0, T.sizeof);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// Go the slow route
|
|
||||||
for (; !range.empty; range.popFront())
|
|
||||||
{
|
|
||||||
range.front = filler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fill(range, T.init);
|
fill(range, T.init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ditto
|
||||||
|
void initializeAll(Range)(Range range)
|
||||||
|
if (is(Range == char[]) || is(Range == wchar[]))
|
||||||
|
{
|
||||||
|
alias ElementEncodingType!Range T;
|
||||||
|
range[] = T.init;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
debug(std_algorithm) scope(success)
|
debug(std_algorithm) scope(success)
|
||||||
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
||||||
int[] a = [ 1, 2, 3 ];
|
|
||||||
uninitializedFill(a, 6);
|
//Test strings:
|
||||||
assert(a == [ 6, 6, 6 ]);
|
//Must work on narrow strings.
|
||||||
initializeAll(a);
|
//Must reject const
|
||||||
assert(a == [ 0, 0, 0 ]);
|
char[3] a = void;
|
||||||
void fun0()
|
a[].initializeAll();
|
||||||
|
assert(a[] == [char.init, char.init, char.init]);
|
||||||
|
string s;
|
||||||
|
assert(!__traits(compiles, s.initializeAll()));
|
||||||
|
|
||||||
|
//Note: Cannot call uninitializedFill on narrow strings
|
||||||
|
|
||||||
|
enum e {e1, e2}
|
||||||
|
e[3] b1 = void;
|
||||||
|
b1[].initializeAll();
|
||||||
|
assert(b1[] == [e.e1, e.e1, e.e1]);
|
||||||
|
e[3] b2 = void;
|
||||||
|
b2[].uninitializedFill(e.e2);
|
||||||
|
assert(b2[] == [e.e2, e.e2, e.e2]);
|
||||||
|
|
||||||
|
static struct S1
|
||||||
{
|
{
|
||||||
foreach (i; 0 .. 1000)
|
int i;
|
||||||
|
}
|
||||||
|
static struct S2
|
||||||
{
|
{
|
||||||
foreach (ref e; a) e = 6;
|
int i = 1;
|
||||||
|
}
|
||||||
|
static struct S3
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
this(this){};
|
||||||
|
}
|
||||||
|
static struct S4
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
this(this){};
|
||||||
|
}
|
||||||
|
static assert (!hasElaborateAssign!S1);
|
||||||
|
static assert (!hasElaborateAssign!S2);
|
||||||
|
static assert ( hasElaborateAssign!S3);
|
||||||
|
static assert ( hasElaborateAssign!S4);
|
||||||
|
assert (!typeid(S1).init().ptr);
|
||||||
|
assert ( typeid(S2).init().ptr);
|
||||||
|
assert (!typeid(S3).init().ptr);
|
||||||
|
assert ( typeid(S4).init().ptr);
|
||||||
|
|
||||||
|
foreach(S; TypeTuple!(S1, S2, S3, S4))
|
||||||
|
{
|
||||||
|
//initializeAll
|
||||||
|
{
|
||||||
|
//Array
|
||||||
|
S[3] ss1 = void;
|
||||||
|
ss1[].initializeAll();
|
||||||
|
assert(ss1[] == [S.init, S.init, S.init]);
|
||||||
|
|
||||||
|
//Not array
|
||||||
|
S[3] ss2 = void;
|
||||||
|
auto sf = ss2[].filter!"true"();
|
||||||
|
|
||||||
|
sf.initializeAll();
|
||||||
|
assert(ss2[] == [S.init, S.init, S.init]);
|
||||||
|
}
|
||||||
|
//uninitializedFill
|
||||||
|
{
|
||||||
|
//Array
|
||||||
|
S[3] ss1 = void;
|
||||||
|
ss1[].uninitializedFill(S(2));
|
||||||
|
assert(ss1[] == [S(2), S(2), S(2)]);
|
||||||
|
|
||||||
|
//Not array
|
||||||
|
S[3] ss2 = void;
|
||||||
|
auto sf = ss2[].filter!"true"();
|
||||||
|
sf.uninitializedFill(S(2));
|
||||||
|
assert(ss2[] == [S(2), S(2), S(2)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void fun1() { foreach (i; 0 .. 1000) fill(a, 6); }
|
|
||||||
//void fun2() { foreach (i; 0 .. 1000) fill2(a, 6); }
|
|
||||||
//writeln(benchmark!(fun0, fun1, fun2)(10000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue