Merge pull request #29 from s-ludwig/alignment_fix
Compute the proper struct alignment for TaggedUnion.
This commit is contained in:
commit
78158dbae8
|
@ -29,7 +29,8 @@ import std.traits : EnumMembers, FieldNameTuple, Unqual, isInstanceOf;
|
|||
$(LI `getFoo` - equivalent to `get!(Kind.foo)`)
|
||||
)
|
||||
*/
|
||||
struct TaggedUnion(U) if (is(U == union) || is(U == struct) || is(U == enum))
|
||||
template TaggedUnion(U) if (is(U == union) || is(U == struct) || is(U == enum)) {
|
||||
align(commonAlignment!(UnionKindTypes!(UnionFieldEnum!U))) struct TaggedUnion
|
||||
{
|
||||
import std.traits : FieldTypeTuple, FieldNameTuple, Largest,
|
||||
hasElaborateCopyConstructor, hasElaborateDestructor, isCopyable;
|
||||
|
@ -294,6 +295,7 @@ struct TaggedUnion(U) if (is(U == union) || is(U == struct) || is(U == enum))
|
|||
|
||||
package @trusted @property ref inout(T) trustedGet(T)() inout { return *cast(inout(T)*)m_data.ptr; }
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@safe nothrow unittest {
|
||||
|
@ -409,6 +411,33 @@ unittest { // non-copyable types
|
|||
tu.setS(S.init);
|
||||
}
|
||||
|
||||
unittest { // alignment
|
||||
union S1 { int v; }
|
||||
union S2 { ulong v; }
|
||||
union S3 { void* v; }
|
||||
|
||||
// sanity check for the actual checks - this may differ on non-x86 architectures
|
||||
static assert(S1.alignof == 4);
|
||||
static assert(S2.alignof == 8);
|
||||
version (D_LP64) static assert(S3.alignof == 8);
|
||||
else static assert(S3.alignof == 4);
|
||||
|
||||
// test external struct alignment
|
||||
static assert(TaggedUnion!S1.alignof == 4);
|
||||
static assert(TaggedUnion!S2.alignof == 8);
|
||||
version (D_LP64) static assert(TaggedUnion!S3.alignof == 8);
|
||||
else static assert(TaggedUnion!S3.alignof == 4);
|
||||
|
||||
// test internal struct alignment
|
||||
TaggedUnion!S1 s1;
|
||||
assert((cast(ubyte*)&s1.vValue() - cast(ubyte*)&s1) % 4 == 0);
|
||||
TaggedUnion!S1 s2;
|
||||
assert((cast(ubyte*)&s2.vValue() - cast(ubyte*)&s2) % 8 == 0);
|
||||
TaggedUnion!S1 s3;
|
||||
version (D_LP64) assert((cast(ubyte*)&s3.vValue() - cast(ubyte*)&s3) % 8 == 0);
|
||||
else assert((cast(ubyte*)&s3.vValue() - cast(ubyte*)&s3) % 4 == 0);
|
||||
}
|
||||
|
||||
|
||||
/** Dispatches the value contained on a `TaggedUnion` to a set of visitors.
|
||||
|
||||
|
@ -751,6 +780,31 @@ package template AmbiguousTypes(Types...) {
|
|||
alias AmbiguousTypes = impl!0;
|
||||
}
|
||||
|
||||
/// Computes the minimum alignment necessary to align all types correctly
|
||||
private size_t commonAlignment(TYPES...)()
|
||||
{
|
||||
import std.numeric : gcd;
|
||||
|
||||
size_t ret = 1;
|
||||
foreach (T; TYPES)
|
||||
ret = (T.alignof * ret) / gcd(T.alignof, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unittest {
|
||||
align(2) struct S1 { ubyte x; }
|
||||
align(4) struct S2 { ubyte x; }
|
||||
align(8) struct S3 { ubyte x; }
|
||||
|
||||
static if (__VERSION__ > 2076) { // DMD 2.076 ignores the alignment
|
||||
assert(commonAlignment!S1 == 2);
|
||||
assert(commonAlignment!S2 == 4);
|
||||
assert(commonAlignment!S3 == 8);
|
||||
assert(commonAlignment!(S1, S3) == 8);
|
||||
assert(commonAlignment!(S1, S2, S3) == 8);
|
||||
assert(commonAlignment!(S2, S2, S1) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
package void rawEmplace(T)(void[] dst, ref T src)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue