mirror of
https://github.com/dlang/phobos.git
synced 2025-05-09 04:27:23 +03:00
Merge pull request #2015 from monarchdodra/emplaceQual
Improve emplaceRef for qualified construction
This commit is contained in:
commit
cecd745cef
3 changed files with 191 additions and 175 deletions
|
@ -799,7 +799,7 @@ template reduce(fun...) if (fun.length >= 1)
|
|||
result = void;
|
||||
foreach (i, T; result.Types)
|
||||
{
|
||||
emplaceRef(result[i], seed);
|
||||
emplaceRef!T(result[i], seed);
|
||||
}
|
||||
r.popFront();
|
||||
return reduce(result, r);
|
||||
|
@ -865,7 +865,7 @@ template reduce(fun...) if (fun.length >= 1)
|
|||
|
||||
foreach (i, T; result.Types)
|
||||
{
|
||||
emplaceRef(result[i], elem);
|
||||
emplaceRef!T(result[i], elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1456,7 +1456,7 @@ void uninitializedFill(Range, Value)(Range range, Value filler)
|
|||
|
||||
// Must construct stuff by the book
|
||||
for (; !range.empty; range.popFront())
|
||||
emplaceRef(range.front, filler);
|
||||
emplaceRef!T(range.front, filler);
|
||||
}
|
||||
else
|
||||
// Doesn't matter whether fill is initialized or not
|
||||
|
|
37
std/array.d
37
std/array.d
|
@ -51,7 +51,7 @@ if (isIterable!Range && !isNarrowString!Range && !isInfinite!Range)
|
|||
size_t i;
|
||||
foreach (e; r)
|
||||
{
|
||||
emplaceRef(result[i], e);
|
||||
emplaceRef!E(result[i], e);
|
||||
++i;
|
||||
}
|
||||
return cast(E[])result;
|
||||
|
@ -110,6 +110,12 @@ unittest
|
|||
static assert(bug12315[0].i == 123456789);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
static struct S{int* p;}
|
||||
auto a = array(immutable(S).init.repeat(5));
|
||||
}
|
||||
|
||||
/**
|
||||
Convert a narrow string to an array type that fully supports random access.
|
||||
This is handled as a special case and always returns a $(D dchar[]),
|
||||
|
@ -1059,13 +1065,13 @@ void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
|
|||
{
|
||||
static if (is(E : T)) //ditto
|
||||
{
|
||||
emplaceRef(tmp[j++], stuff[i]);
|
||||
emplaceRef!T(tmp[j++], stuff[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (v; stuff[i])
|
||||
{
|
||||
emplaceRef(tmp[j++], v);
|
||||
emplaceRef!T(tmp[j++], v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2434,12 +2440,7 @@ struct Appender(A : T[], T)
|
|||
auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. len + 1];}
|
||||
auto bigData = bigDataFun();
|
||||
|
||||
static if (is(Unqual!T == T))
|
||||
alias uitem = item;
|
||||
else
|
||||
auto ref uitem() @trusted nothrow @property { return cast(Unqual!T)item;}
|
||||
|
||||
emplaceRef(bigData[len], uitem);
|
||||
emplaceRef!T(bigData[len], item);
|
||||
|
||||
//We do this at the end, in case of exceptions
|
||||
_data.arr = bigData;
|
||||
|
@ -2484,28 +2485,18 @@ struct Appender(A : T[], T)
|
|||
auto bigDataFun() @trusted nothrow { return _data.arr.ptr[0 .. newlen];}
|
||||
auto bigData = bigDataFun();
|
||||
|
||||
enum mustEmplace = is(typeof(bigData[0].opAssign(cast(Unqual!T)items.front))) ||
|
||||
!is(typeof(bigData[0] = cast(Unqual!T)items.front));
|
||||
alias UT = Unqual!T;
|
||||
|
||||
static if (is(typeof(_data.arr[] = items[])) && !mustEmplace)
|
||||
static if (is(typeof(_data.arr[] = items[])) &&
|
||||
!hasElaborateAssign!(Unqual!T) && isAssignable!(UT, ElementEncodingType!Range))
|
||||
{
|
||||
//pragma(msg, T.stringof); pragma(msg, Range.stringof);
|
||||
bigData[len .. newlen] = items[];
|
||||
}
|
||||
else static if (is(Unqual!T == ElementType!Range))
|
||||
{
|
||||
foreach (ref it ; bigData[len .. newlen])
|
||||
{
|
||||
emplaceRef(it, items.front);
|
||||
items.popFront();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static auto ref getUItem(U)(U item) @trusted {return cast(Unqual!T)item;}
|
||||
foreach (ref it ; bigData[len .. newlen])
|
||||
{
|
||||
emplaceRef(it, getUItem(items.front));
|
||||
emplaceRef!T(it, items.front);
|
||||
items.popFront();
|
||||
}
|
||||
}
|
||||
|
|
111
std/conv.d
111
std/conv.d
|
@ -3845,56 +3845,56 @@ emplace, but takes its argument by ref (as opposed to "by pointer").
|
|||
|
||||
This makes it easier to use, easier to be safe, and faster in a non-inline
|
||||
build.
|
||||
+/
|
||||
package ref T emplaceRef(T)(ref T chunk)
|
||||
{
|
||||
static assert (is(T* : void*),
|
||||
format("Cannot emplace a %s because it is qualified.", T.stringof));
|
||||
|
||||
Furthermore, emplaceRef takes a type paremeter, which specifies the type we
|
||||
want to build. This helps to build qualified objects on mutable buffer,
|
||||
without breaking the type system with unsafe casts.
|
||||
+/
|
||||
package template emplaceRef(T)
|
||||
{
|
||||
alias UT = Unqual!T;
|
||||
|
||||
ref UT emplaceRef()(ref UT chunk)
|
||||
{
|
||||
static assert (is(typeof({static T i;})),
|
||||
format("Cannot emplace a %1$s because %1$s.this() is annotated with @disable.", T.stringof));
|
||||
|
||||
return emplaceInitializer(chunk);
|
||||
}
|
||||
// ditto
|
||||
package ref T emplaceRef(T, Args...)(ref T chunk, auto ref Args args)
|
||||
if (!is(T == struct) && Args.length == 1)
|
||||
|
||||
static if (!is(T == struct))
|
||||
ref UT emplaceRef(Arg)(ref UT chunk, auto ref Arg arg)
|
||||
{
|
||||
alias Arg = Args[0];
|
||||
alias arg = args[0];
|
||||
|
||||
static assert (is(T* : void*),
|
||||
format("Cannot emplace a %s because it is qualified.", T.stringof));
|
||||
|
||||
static assert(is(typeof({T t = args[0];})),
|
||||
static assert(is(typeof({T t = arg;})),
|
||||
format("%s cannot be emplaced from a %s.", T.stringof, Arg.stringof));
|
||||
|
||||
static if (isStaticArray!T)
|
||||
{
|
||||
alias UArg = Unqual!Arg;
|
||||
alias E = typeof(chunk.ptr[0]);
|
||||
alias E = ElementEncodingType!(typeof(T.init[]));
|
||||
alias UE = Unqual!E;
|
||||
enum N = T.length;
|
||||
|
||||
static if (is(Arg : T))
|
||||
{
|
||||
//Matching static array
|
||||
static if (!hasElaborateAssign!T && isAssignable!(T, Arg))
|
||||
static if (!hasElaborateAssign!UT && isAssignable!(UT, Arg))
|
||||
chunk = arg;
|
||||
else static if (is(UArg == T))
|
||||
else static if (is(UArg == UT))
|
||||
{
|
||||
memcpy(&chunk, &arg, T.sizeof);
|
||||
static if (hasElaborateCopyConstructor!T)
|
||||
typeid(T).postblit(cast(void*)&chunk);
|
||||
}
|
||||
else
|
||||
emplaceRef(chunk, cast(T)arg);
|
||||
.emplaceRef!T(chunk, cast(T)arg);
|
||||
}
|
||||
else static if (is(Arg : E[]))
|
||||
{
|
||||
//Matching dynamic array
|
||||
static if (!hasElaborateAssign!T && is(typeof(chunk[] = arg[])))
|
||||
static if (!hasElaborateAssign!UT && is(typeof(chunk[] = arg[])))
|
||||
chunk[] = arg[];
|
||||
else static if (is(UArg == E[]))
|
||||
else static if (is(Unqual!(ElementEncodingType!Arg) == UE))
|
||||
{
|
||||
assert(N == chunk.length, "Array length missmatch in emplace");
|
||||
memcpy(cast(void*)&chunk, arg.ptr, T.sizeof);
|
||||
|
@ -3902,14 +3902,14 @@ if (!is(T == struct) && Args.length == 1)
|
|||
typeid(T).postblit(cast(void*)&chunk);
|
||||
}
|
||||
else
|
||||
emplaceRef(chunk, cast(E[])arg);
|
||||
.emplaceRef!T(chunk, cast(E[])arg);
|
||||
}
|
||||
else static if (is(Arg : E))
|
||||
{
|
||||
//Case matching single element to array.
|
||||
static if (!hasElaborateAssign!T && is(typeof(chunk[] = arg)))
|
||||
static if (!hasElaborateAssign!UT && is(typeof(chunk[] = arg)))
|
||||
chunk[] = arg;
|
||||
else static if (is(UArg == E))
|
||||
else static if (is(UArg == Unqual!E))
|
||||
{
|
||||
//Note: We copy everything, and then postblit just once.
|
||||
//This is as exception safe as what druntime can provide us.
|
||||
|
@ -3920,18 +3920,18 @@ if (!is(T == struct) && Args.length == 1)
|
|||
}
|
||||
else
|
||||
//Alias this. Coerce.
|
||||
emplaceRef(chunk, cast(E)arg);
|
||||
.emplaceRef!T(chunk, cast(E)arg);
|
||||
}
|
||||
else static if (is(typeof(emplaceRef(chunk[0], arg))))
|
||||
else static if (is(typeof(.emplaceRef!E(chunk[0], arg))))
|
||||
{
|
||||
//Final case for everything else:
|
||||
//Types that don't match (int to uint[2])
|
||||
//Recursion for multidimensions
|
||||
static if (!hasElaborateAssign!T && is(typeof(chunk[] = arg)))
|
||||
static if (!hasElaborateAssign!UT && is(typeof(chunk[] = arg)))
|
||||
chunk[] = arg;
|
||||
else
|
||||
foreach(i; 0 .. N)
|
||||
emplaceRef(chunk[i], arg);
|
||||
.emplaceRef!E(chunk[i], arg);
|
||||
}
|
||||
else
|
||||
static assert(0, format("Sorry, this implementation doesn't know how to emplace a %s with a %s", T.stringof, Arg.stringof));
|
||||
|
@ -3945,20 +3945,17 @@ if (!is(T == struct) && Args.length == 1)
|
|||
}
|
||||
}
|
||||
// ditto
|
||||
package ref T emplaceRef(T, Args...)(ref T chunk, auto ref Args args)
|
||||
if (is(T == struct))
|
||||
static if (is(T == struct))
|
||||
ref UT emplaceRef(Args...)(ref UT chunk, auto ref Args args)
|
||||
{
|
||||
static assert (is(T* : void*),
|
||||
format("Cannot emplace a %s because it is qualified.", T.stringof));
|
||||
|
||||
static if (Args.length == 1 && is(Args[0] : T) &&
|
||||
is (typeof({T t = args[0];})) //Check for legal postblit
|
||||
)
|
||||
{
|
||||
static if (is(T == Unqual!(Args[0])))
|
||||
static if (is(Unqual!T == Unqual!(Args[0])))
|
||||
{
|
||||
//Types match exactly: we postblit
|
||||
static if (!hasElaborateAssign!T && isAssignable!T)
|
||||
static if (!hasElaborateAssign!UT && isAssignable!(UT, T))
|
||||
chunk = args[0];
|
||||
else
|
||||
{
|
||||
|
@ -3969,7 +3966,7 @@ if (is(T == struct))
|
|||
}
|
||||
else
|
||||
//Alias this. Coerce to type T.
|
||||
emplaceRef(chunk, cast(T)args[0]);
|
||||
.emplaceRef!T(chunk, cast(T)args[0]);
|
||||
}
|
||||
else static if (is(typeof(chunk.__ctor(args))))
|
||||
{
|
||||
|
@ -3991,10 +3988,11 @@ if (is(T == struct))
|
|||
foreach (i, ref field; chunk.tupleof[0 .. Args.length])
|
||||
{
|
||||
alias Field = typeof(field);
|
||||
static if (is(Field == Unqual!Field))
|
||||
emplaceRef(field, args[i]);
|
||||
alias UField = Unqual!Field;
|
||||
static if (is(Field == UField))
|
||||
.emplaceRef!Field(field, args[i]);
|
||||
else
|
||||
emplaceRef(*cast(Unqual!Field*)&field, args[i]);
|
||||
.emplaceRef!Field(*cast(Unqual!Field*)&field, args[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -4010,6 +4008,7 @@ if (is(T == struct))
|
|||
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
//emplace helper functions
|
||||
private ref T emplaceInitializer(T)(ref T chunk) @trusted pure nothrow
|
||||
{
|
||||
|
@ -4027,7 +4026,7 @@ ref T emplaceOpCaller(T, Args...)(ref T chunk, auto ref Args args)
|
|||
{
|
||||
static assert (is(typeof({T t = T.opCall(args);})),
|
||||
format("%s.opCall does not return adequate data for construction.", T.stringof));
|
||||
return emplaceRef(chunk, chunk.opCall(args));
|
||||
return emplaceRef!T(chunk, chunk.opCall(args));
|
||||
}
|
||||
|
||||
|
||||
|
@ -4042,7 +4041,7 @@ as $(D chunk)).
|
|||
*/
|
||||
T* emplace(T)(T* chunk) @safe nothrow pure
|
||||
{
|
||||
emplaceRef(*chunk);
|
||||
emplaceRef!T(*chunk);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
@ -4060,14 +4059,14 @@ as $(D chunk)).
|
|||
T* emplace(T, Args...)(T* chunk, auto ref Args args)
|
||||
if (!is(T == struct) && Args.length == 1)
|
||||
{
|
||||
emplaceRef(*chunk, args);
|
||||
emplaceRef!T(*chunk, args);
|
||||
return chunk;
|
||||
}
|
||||
/// ditto
|
||||
T* emplace(T, Args...)(T* chunk, auto ref Args args)
|
||||
if (is(T == struct))
|
||||
{
|
||||
emplaceRef(*chunk, args);
|
||||
emplaceRef!T(*chunk, args);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
@ -4858,6 +4857,32 @@ unittest
|
|||
emplace(&sss, s);
|
||||
}
|
||||
|
||||
unittest //Constness
|
||||
{
|
||||
import std.stdio;
|
||||
|
||||
int a = void;
|
||||
emplaceRef!(const int)(a, 5);
|
||||
|
||||
immutable i = 5;
|
||||
const(int)* p = void;
|
||||
emplaceRef!(const int*)(p, &i);
|
||||
|
||||
struct S
|
||||
{
|
||||
int* p;
|
||||
}
|
||||
alias IS = immutable(S);
|
||||
S s = void;
|
||||
emplaceRef!IS(s, IS());
|
||||
S[2] ss = void;
|
||||
emplaceRef!(IS[2])(ss, IS());
|
||||
|
||||
IS[2] iss = IS.init;
|
||||
emplaceRef!(IS[2])(ss, iss);
|
||||
emplaceRef!(IS[2])(ss, iss[]);
|
||||
}
|
||||
|
||||
private void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName)
|
||||
{
|
||||
enforceEx!ConvException(chunk.length >= typeSize,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue