From 614751003b12c2a409e2b6d89b4360dadf52cad8 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 18:41:02 +0400 Subject: [PATCH 01/27] Position unittests just after `emplace` they test --- std/conv.d | 116 +++++++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 56 deletions(-) diff --git a/std/conv.d b/std/conv.d index 4a194962fb2..c552f8a045f 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3437,6 +3437,34 @@ T* emplace(T, Args...)(T* chunk, Args args) return chunk; } +unittest +{ + debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); + int a; + int b = 42; + assert(*emplace!int(&a, b) == 42); +} + +unittest +{ + interface I {} + class K : I {} + + K k = void; + emplace!K(&k); + assert(k is null); + K k2 = new K; + assert(k2 !is null); + emplace!K(&k, k2); + assert(k is k2); + + I i = void; + emplace!I(&i); + assert(i is null); + emplace!I(&i, k); + assert(i is k); +} + // Specialization for struct T* emplace(T, Args...)(T* chunk, Args args) if (is(T == struct)) @@ -3472,6 +3500,38 @@ T* emplace(T, Args...)(T* chunk, Args args) return result; } +unittest +{ + debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); + struct S + { + double x = 5, y = 6; + this(int a, int b) + { + assert(x == 5 && y == 6); + x = a; + y = b; + } + } + + auto s1 = new void[S.sizeof]; + auto s2 = S(42, 43); + assert(*emplace!S(cast(S*) s1.ptr, s2) == s2); + assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45)); +} + +unittest +{ + struct Foo + { + uint num; + } + + Foo foo; + emplace!Foo(&foo, 2U); + assert(foo.num == 2); +} + /** Given a raw memory area $(D chunk), constructs an object of $(D class) type $(D T) at that address. The constructor is passed the arguments @@ -3550,30 +3610,6 @@ unittest assert(s1.a == 42 && s1.b == 43); } -unittest -{ - debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); - int a; - int b = 42; - assert(*emplace!int(&a, b) == 42); - - struct S - { - double x = 5, y = 6; - this(int a, int b) - { - assert(x == 5 && y == 6); - x = a; - y = b; - } - } - - auto s1 = new void[S.sizeof]; - auto s2 = S(42, 43); - assert(*emplace!S(cast(S*) s1.ptr, s2) == s2); - assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45)); -} - unittest { debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); @@ -3610,38 +3646,6 @@ unittest assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345])); } -unittest -{ - struct Foo - { - uint num; - } - - Foo foo; - emplace!Foo(&foo, 2U); - assert(foo.num == 2); -} - -unittest -{ - interface I {} - class K : I {} - - K k = void; - emplace!K(&k); - assert(k is null); - K k2 = new K; - assert(k2 !is null); - emplace!K(&k, k2); - assert(k is k2); - - I i = void; - emplace!I(&i); - assert(i is null); - emplace!I(&i, k); - assert(i is k); -} - // Undocumented for the time being void toTextRange(T, W)(T value, W writer) if (isIntegral!T && isOutputRange!(W, char)) From d207cd00e1fa200ba823722066fa40cf13d70cbd Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 18:44:33 +0400 Subject: [PATCH 02/27] Divide unittest and position its parts just after `emplace` they test --- std/conv.d | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/std/conv.d b/std/conv.d index c552f8a045f..de3080a1df1 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3418,6 +3418,20 @@ T* emplace(T)(T* chunk) return chunk; } +unittest +{ + interface I {} + class K : I {} + + K k = void; + emplace!K(&k); + assert(k is null); + + I i = void; + emplace!I(&i); + assert(i is null); +} + /** Given a pointer $(D chunk) to uninitialized memory (but already typed @@ -3450,17 +3464,13 @@ unittest interface I {} class K : I {} - K k = void; - emplace!K(&k); - assert(k is null); - K k2 = new K; - assert(k2 !is null); + K k = null, k2 = new K; + assert(k !is k2); emplace!K(&k, k2); assert(k is k2); - I i = void; - emplace!I(&i); - assert(i is null); + I i = null; + assert(i !is k); emplace!I(&i, k); assert(i is k); } From 6639900267df5041c462665f614fc34b3ccd7445 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 18:50:37 +0400 Subject: [PATCH 03/27] Refactor `emplace` --- std/conv.d | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/std/conv.d b/std/conv.d index de3080a1df1..515fb666555 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3405,10 +3405,9 @@ as $(D chunk)). T* emplace(T)(T* chunk) if (!is(T == class)) { - auto result = cast(typeof(return)) chunk; static T i; - memcpy(result, &i, T.sizeof); - return result; + memcpy(chunk, &i, T.sizeof); + return chunk; } ///ditto T* emplace(T)(T* chunk) @@ -3479,35 +3478,33 @@ unittest T* emplace(T, Args...)(T* chunk, Args args) if (is(T == struct)) { - auto result = cast(typeof(return)) chunk; - void initialize() { static T i; memcpy(chunk, &i, T.sizeof); } - static if (is(typeof(result.__ctor(args)))) + static if (is(typeof(chunk.__ctor(args)))) { // T defines a genuine constructor accepting args // Go the classic route: write .init first, then call ctor initialize(); - result.__ctor(args); + chunk.__ctor(args); } else static if (is(typeof(T(args)))) { // Struct without constructor that has one matching field for // each argument - *result = T(args); + *chunk = T(args); } else //static if (Args.length == 1 && is(Args[0] : T)) { static assert(Args.length == 1); //static assert(0, T.stringof ~ " " ~ Args.stringof); // initialize(); - *result = args[0]; + *chunk = args[0]; } - return result; + return chunk; } unittest @@ -3562,7 +3559,7 @@ T emplace(T, Args...)(void[] chunk, Args args) if (is(T == class)) new ConvException("emplace: chunk size too small")); auto a = cast(size_t) chunk.ptr; enforce(a % T.alignof == 0, text(a, " vs. ", T.alignof)); - auto result = cast(typeof(return)) chunk.ptr; + auto result = cast(T) chunk.ptr; // Initialize the object in its pre-ctor state (cast(byte[]) chunk)[0 .. classSize] = typeid(T).init[]; @@ -3602,8 +3599,7 @@ T* emplace(T, Args...)(void[] chunk, Args args) new ConvException("emplace: chunk size too small")); auto a = cast(size_t) chunk.ptr; enforce(a % T.alignof == 0, text(a, " vs. ", T.alignof)); - auto result = cast(typeof(return)) chunk.ptr; - return emplace(result, args); + return emplace(cast(T*) chunk.ptr, args); } unittest From e62b241351d0510f2373d35f28394507ba9a10ff Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 19:10:25 +0400 Subject: [PATCH 04/27] Fix `emplace` issue with structs with disabled ctors --- std/conv.d | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/std/conv.d b/std/conv.d index 515fb666555..b18e1e0ec47 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3417,6 +3417,28 @@ T* emplace(T)(T* chunk) return chunk; } +version(unittest) struct EmplaceTest +{ + int i = 3; + this(int i) + { + assert(this.i == 3 && i == 5); + this.i = i; + } + +@disable: + this(); + this(this); + void opAssign(); +} + +unittest +{ + struct S { @disable this(); } + S s = void; + static assert(!__traits(compiles, emplace(&s))); +} + unittest { interface I {} @@ -3480,8 +3502,10 @@ T* emplace(T, Args...)(T* chunk, Args args) { void initialize() { - static T i; - memcpy(chunk, &i, T.sizeof); + if(auto p = typeid(T).init().ptr) + memcpy(chunk, p, T.sizeof); + else + memset(chunk, 0, T.sizeof); } static if (is(typeof(chunk.__ctor(args)))) @@ -3527,6 +3551,13 @@ unittest assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45)); } +unittest +{ + EmplaceTest k = void; + emplace(&k, 5); + assert(k.i == 5); +} + unittest { struct Foo From 63503202b74a5e97e7755847feac886db0bbe64f Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 19:20:23 +0400 Subject: [PATCH 05/27] Fix `emplace` part of issue 6436 * Issue URL: http://d.puremagic.com/issues/show_bug.cgi?id=6436 --- std/conv.d | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/std/conv.d b/std/conv.d index b18e1e0ec47..0473e7d1a41 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3425,6 +3425,12 @@ version(unittest) struct EmplaceTest assert(this.i == 3 && i == 5); this.i = i; } + this(int i, ref int j) + { + assert(i == 5 && j == 6); + this.i = i; + ++j; + } @disable: this(); @@ -3432,6 +3438,22 @@ version(unittest) struct EmplaceTest void opAssign(); } +version(unittest) class EmplaceTestClass +{ + int i = 3; + this(int i) + { + assert(this.i == 3 && i == 5); + this.i = i; + } + this(int i, ref int j) + { + assert(i == 5 && j == 6); + this.i = i; + ++j; + } +} + unittest { struct S { @disable this(); } @@ -3497,7 +3519,7 @@ unittest } // Specialization for struct -T* emplace(T, Args...)(T* chunk, Args args) +T* emplace(T, Args...)(T* chunk, auto ref Args args) if (is(T == struct)) { void initialize() @@ -3558,6 +3580,15 @@ unittest assert(k.i == 5); } +unittest +{ + int var = 6; + EmplaceTest k = void; + emplace(&k, 5, var); + assert(k.i == 5); + assert(var == 7); +} + unittest { struct Foo @@ -3583,7 +3614,7 @@ $(D T) is $(D @safe). Returns: A pointer to the newly constructed object. */ -T emplace(T, Args...)(void[] chunk, Args args) if (is(T == class)) +T emplace(T, Args...)(void[] chunk, auto ref Args args) if (is(T == class)) { enum classSize = __traits(classInstanceSize, T); enforce(chunk.length >= classSize, @@ -3611,6 +3642,14 @@ T emplace(T, Args...)(void[] chunk, Args args) if (is(T == class)) return result; } +unittest +{ + int var = 6; + auto k = emplace!EmplaceTestClass(new void[__traits(classInstanceSize, EmplaceTestClass)], 5, var); + assert(k.i == 5); + assert(var == 7); +} + /** Given a raw memory area $(D chunk), constructs an object of non-$(D class) type $(D T) at that address. The constructor is passed the @@ -3623,7 +3662,7 @@ $(D T) is $(D @safe). Returns: A pointer to the newly constructed object. */ -T* emplace(T, Args...)(void[] chunk, Args args) +T* emplace(T, Args...)(void[] chunk, auto ref Args args) if (!is(T == class)) { enforce(chunk.length >= T.sizeof, @@ -3647,6 +3686,14 @@ unittest assert(s1.a == 42 && s1.b == 43); } +unittest +{ + int var = 6; + auto k = emplace!EmplaceTest(new void[EmplaceTest.sizeof], 5, var); + assert(k.i == 5); + assert(var == 7); +} + unittest { debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); From 98061d298e8f3e63e19fd4b5cc10f05061025be9 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 19:56:25 +0400 Subject: [PATCH 06/27] Create `std.traits.classInstanceAlignment` --- std/traits.d | 37 +++++++++++++++++++++++++++++++++++++ std/typecons.d | 10 +--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/std/traits.d b/std/traits.d index daeca45d31d..edbd6f29a07 100644 --- a/std/traits.d +++ b/std/traits.d @@ -2781,6 +2781,43 @@ unittest } +private template maxAlignment(U...) if(isTypeTuple!U) +{ + static if(U.length == 1) + enum maxAlignment = U[0].alignof; + else + enum maxAlignment = max(U[0].alignof, .maxAlignment!(U[1 .. $])); +} + + +/** +Returns class instance alignment. + +Example: +--- +class A { byte b; } +class B { long l; } + +// As class instancec always has a hidden pointer +static assert(classInstanceAlignment!A == (void*).alignof); +static assert(classInstanceAlignment!B == long.alignof); +--- + */ +template classInstanceAlignment(T) if(is(T == class)) +{ + alias maxAlignment!(void*, typeof(T.tupleof)) classInstanceAlignment; +} + +unittest +{ + class A { byte b; } + class B { long l; } + + static assert(classInstanceAlignment!A == (void*).alignof); + static assert(classInstanceAlignment!B == long.alignof); +} + + //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// // Type Conversion //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// diff --git a/std/typecons.d b/std/typecons.d index 3601c5fb8bc..cf773ee350a 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3069,7 +3069,7 @@ unittest { // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for // small objects). We will just use the maximum of filed alignments. - alias maxAlignment!(void*, typeof(T.tupleof)) alignment; + alias classInstanceAlignment!T alignment; static size_t aligned(size_t n) { @@ -3103,14 +3103,6 @@ unittest return result; } -private template maxAlignment(U...) if(isTypeTuple!U) -{ - static if(U.length == 1) - enum maxAlignment = U[0].alignof; - else - enum maxAlignment = max(U[0].alignof, .maxAlignment!(U[1 .. $])); -} - unittest // Issue 6580 testcase { enum alignment = (void*).alignof; From 524fe42efc77cf67f8cd12539d58aecee456d3a0 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 20:11:51 +0400 Subject: [PATCH 07/27] Segregate `std.conv.testEmplaceChunk` function --- std/conv.d | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/std/conv.d b/std/conv.d index 0473e7d1a41..72791386e5a 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3601,6 +3601,16 @@ unittest assert(foo.num == 2); } +private void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName) +{ + enforceEx!ConvException(chunk.length >= typeSize, + xformat("emplace: Chunk size too small: %s < %s size = %s", + chunk.length, typeName, typeSize)); + enforceEx!ConvException((cast(size_t) chunk.ptr) % typeAlignment == 0, + xformat("emplace: Misaligned memory block (0x%X): it must be %s-byte aligned for type %s", + chunk.ptr, typeAlignment, typeName)); +} + /** Given a raw memory area $(D chunk), constructs an object of $(D class) type $(D T) at that address. The constructor is passed the arguments @@ -3617,10 +3627,7 @@ Returns: A pointer to the newly constructed object. T emplace(T, Args...)(void[] chunk, auto ref Args args) if (is(T == class)) { enum classSize = __traits(classInstanceSize, T); - enforce(chunk.length >= classSize, - new ConvException("emplace: chunk size too small")); - auto a = cast(size_t) chunk.ptr; - enforce(a % T.alignof == 0, text(a, " vs. ", T.alignof)); + testEmplaceChunk(chunk, classSize, T.alignof, T.stringof); auto result = cast(T) chunk.ptr; // Initialize the object in its pre-ctor state @@ -3665,10 +3672,7 @@ Returns: A pointer to the newly constructed object. T* emplace(T, Args...)(void[] chunk, auto ref Args args) if (!is(T == class)) { - enforce(chunk.length >= T.sizeof, - new ConvException("emplace: chunk size too small")); - auto a = cast(size_t) chunk.ptr; - enforce(a % T.alignof == 0, text(a, " vs. ", T.alignof)); + testEmplaceChunk(chunk, T.sizeof, T.alignof, T.stringof); return emplace(cast(T*) chunk.ptr, args); } From 4bc219451bac54d1b61e14ecd3e3dd2bdcd6c419 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 20:12:35 +0400 Subject: [PATCH 08/27] Fix Issue 6635 - std.conv.emplace: enforcement is too weak * Issue URL: http://d.puremagic.com/issues/show_bug.cgi?id=6635 --- std/conv.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/conv.d b/std/conv.d index 72791386e5a..6c939868a90 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3627,7 +3627,7 @@ Returns: A pointer to the newly constructed object. T emplace(T, Args...)(void[] chunk, auto ref Args args) if (is(T == class)) { enum classSize = __traits(classInstanceSize, T); - testEmplaceChunk(chunk, classSize, T.alignof, T.stringof); + testEmplaceChunk(chunk, classSize, classInstanceAlignment!T, T.stringof); auto result = cast(T) chunk.ptr; // Initialize the object in its pre-ctor state From dab3b2a7dda8459b5f609761a984811d3e7aec5d Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 20:29:58 +0400 Subject: [PATCH 09/27] Fix Issue 6436 - Refcounted initialization bug * Issue URL: http://d.puremagic.com/issues/show_bug.cgi?id=6436 --- std/typecons.d | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index cf773ee350a..c7e15899ec4 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -2478,7 +2478,7 @@ if (!is(T == class)) private Impl* _store; - private void initialize(A...)(A args) + private void initialize(A...)(auto ref A args) { _store = cast(Impl*) enforce(malloc(Impl.sizeof)); if (hasIndirections!T) @@ -2533,7 +2533,7 @@ Constructor that initializes the payload. Postcondition: $(D refCountedIsInitialized) */ - this(A...)(A args) if (A.length > 0) + this(A...)(auto ref A args) if (A.length > 0) { _refCounted.initialize(args); } @@ -2704,6 +2704,16 @@ unittest alias RefCounted!S SRC; } +// 6436 +unittest +{ + struct S { this(ref int val) { assert(val == 3); ++val; } } + + int val = 3; + auto s = RefCounted!S(val); + assert(val == 4); +} + unittest { RefCounted!int a; From 9cf123aff32a09cc766202bef13a77c6c1a05e21 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 23:01:30 +0400 Subject: [PATCH 10/27] Fix terrible `std.typecons.scoped` bug For misaligned buffer it emplaces object to incorrect memory location. --- std/typecons.d | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index c7e15899ec4..83d075cac7c 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3109,7 +3109,8 @@ unittest } Scoped!T result; - emplace!(Unqual!T)(cast(void[])result.Scoped_store, args); + immutable size_t d = cast(void*) result.Scoped_payload - result.Scoped_store.ptr; + emplace!(Unqual!T)(result.Scoped_store[d .. $], args); return result; } From 2840e44b21a3e5617069a1fd7f894282e229e48c Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Fri, 26 Oct 2012 23:05:47 +0400 Subject: [PATCH 11/27] Fix `std.typecons.scoped` issue similar to `RefCounted` issue 6436. * Issue URL: http://d.puremagic.com/issues/show_bug.cgi?id=6436 --- std/typecons.d | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index 83d075cac7c..1e9740ecb0e 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3071,7 +3071,7 @@ unittest } ---- */ -@system auto scoped(T, Args...)(Args args) if (is(T == class)) +@system auto scoped(T, Args...)(auto ref Args args) if (is(T == class)) { static struct Scoped(T) { @@ -3324,6 +3324,15 @@ unittest static assert(is(typeof(c3.foo) == immutable(int))); } +unittest +{ + class C { this(ref int val) { assert(val == 3); ++val; } } + + int val = 3; + auto s = scoped!C(val); + assert(val == 4); +} + /** Defines a simple, self-documenting yes/no flag. This makes it easy for APIs to define functions accepting flags without resorting to $(D From 10375d681ba2f5c6114689fb341cf1d24a519d66 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sat, 27 Oct 2012 10:36:53 +0400 Subject: [PATCH 12/27] Add comments to `emplace` unittests --- std/conv.d | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/std/conv.d b/std/conv.d index 6c939868a90..a256c14036e 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3553,6 +3553,8 @@ T* emplace(T, Args...)(T* chunk, auto ref Args args) return chunk; } +// Test constructor branch + unittest { debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded."); @@ -3589,6 +3591,8 @@ unittest assert(var == 7); } +// Test matching fields branch + unittest { struct Foo @@ -3601,6 +3605,10 @@ unittest assert(foo.num == 2); } +// Test assignment branch + +// FIXME: no tests + private void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName) { enforceEx!ConvException(chunk.length >= typeSize, From ca9ef194a4cef77e73fff1f97737822cc45ede2f Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sat, 27 Oct 2012 10:46:45 +0400 Subject: [PATCH 13/27] Improve `emplace` unittests --- std/conv.d | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/std/conv.d b/std/conv.d index a256c14036e..679826a2400 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3595,14 +3595,17 @@ unittest unittest { - struct Foo - { - uint num; - } + struct S { uint n; } + S s; + emplace!S(&s, 2U); + assert(s.n == 2); +} - Foo foo; - emplace!Foo(&foo, 2U); - assert(foo.num == 2); +unittest +{ + struct S { int a, b; this(int){} } + S s; + static assert(!__traits(compiles, emplace!S(&s, 2, 3))); } // Test assignment branch From 4269dd53c484650ffe844602bdf8e4e169327e5b Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sat, 27 Oct 2012 10:52:36 +0400 Subject: [PATCH 14/27] Add unittest for `emplace` with struct without constructor --- std/conv.d | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/std/conv.d b/std/conv.d index 679826a2400..fab35aa214e 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3608,6 +3608,18 @@ unittest static assert(!__traits(compiles, emplace!S(&s, 2, 3))); } +unittest +{ + struct S { int a, b = 7; } + S s1 = void, s2 = void; + + emplace!S(&s1, 2); + assert(s1.a == 2 && s1.b == 7); + + emplace!S(&s2, 2, 3); + assert(s2.a == 2 && s2.b == 3); +} + // Test assignment branch // FIXME: no tests From b3d3c44cc1e879b6ca6850abf94df5ffb6fc37b0 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 28 Oct 2012 11:42:32 +0400 Subject: [PATCH 15/27] Fix `std.typecons.scoped` name clashes issue One was unable to call `alignment` or `aligned` class members because `Scoped(T)` struct has such private members and name lookup is done before protection resolution. --- std/typecons.d | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 1e9740ecb0e..6a4dd240710 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3073,22 +3073,20 @@ unittest */ @system auto scoped(T, Args...)(auto ref Args args) if (is(T == class)) { - static struct Scoped(T) + // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for + // small objects). We will just use the maximum of filed alignments. + alias classInstanceAlignment!T alignment; + + static size_t aligned(size_t n) { - private - { - // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for - // small objects). We will just use the maximum of filed alignments. - alias classInstanceAlignment!T alignment; + enum badEnd = alignment - 1; // 0b11, 0b111, ... + return (n + badEnd) & ~badEnd; + } - static size_t aligned(size_t n) - { - enum badEnd = alignment - 1; // 0b11, 0b111, ... - return (n + badEnd) & ~badEnd; - } + static struct Scoped(T) + { + private void[aligned(__traits(classInstanceSize, T)) + alignment] Scoped_store = void; - void[aligned(__traits(classInstanceSize, T)) + alignment] Scoped_store = void; - } @property inout(T) Scoped_payload() inout { return cast(inout(T)) cast(void*) aligned(cast(size_t) Scoped_store.ptr); From deb33d0f7949d640d7b30f41b883cd370be29234 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 28 Oct 2012 11:51:42 +0400 Subject: [PATCH 16/27] Remove outdated comment from `std.typecons.scoped` unittest. --- std/typecons.d | 1 - 1 file changed, 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index 6a4dd240710..52408949bfd 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3135,7 +3135,6 @@ unittest // Issue 6580 testcase void alignmentTest() { - // Enshure `forAlignmentOnly` field really helps auto c1long = scoped!C1long(); auto c2long = scoped!C2long(); assert(cast(size_t)&c1long.l % longAlignment == 0); From 3e0f69c3df5d10d9c4b2f62096f0b6947e84abe3 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 28 Oct 2012 12:05:45 +0400 Subject: [PATCH 17/27] Added unittests for fixed `std.typecons.scoped` alignment issue. * issue fixed in commit 9cf123aff32a09cc766202bef13a77c6c1a05e21 --- std/typecons.d | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 52408949bfd..581c5ed6212 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3128,17 +3128,24 @@ unittest // Issue 6580 testcase static assert(scoped!C7().sizeof % alignment == 0); enum longAlignment = long.alignof; - static class C1long { long l; byte b; } - static class C2long { byte[2] b; long l; } + static class C1long + { + long l; byte b = 4; + this() { } + this(long _l) { l = _l; } + } + static class C2long { byte[2] b = [5, 6]; long l = 7; } static assert(scoped!C1long().sizeof % longAlignment == 0); static assert(scoped!C2long().sizeof % longAlignment == 0); void alignmentTest() { - auto c1long = scoped!C1long(); + auto c1long = scoped!C1long(3); auto c2long = scoped!C2long(); assert(cast(size_t)&c1long.l % longAlignment == 0); assert(cast(size_t)&c2long.l % longAlignment == 0); + assert(c1long.l == 3 && c1long.b == 4); + assert(c2long.b == [5, 6] && c2long.l == 7); } alignmentTest(); From 95c5ba378ce12648a82b27bbf204d7bfb61118c7 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 28 Oct 2012 12:08:14 +0400 Subject: [PATCH 18/27] Added unittests for fixed `std.typecons.scoped` initialization issue. * issue fixed in commit 2840e44b21a3e5617069a1fd7f894282e229e48c --- std/typecons.d | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 581c5ed6212..f9e1414307a 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3132,7 +3132,7 @@ unittest // Issue 6580 testcase { long l; byte b = 4; this() { } - this(long _l) { l = _l; } + this(long _l, ref int i) { l = _l; ++i; } } static class C2long { byte[2] b = [5, 6]; long l = 7; } static assert(scoped!C1long().sizeof % longAlignment == 0); @@ -3140,7 +3140,9 @@ unittest // Issue 6580 testcase void alignmentTest() { - auto c1long = scoped!C1long(3); + int var = 5; + auto c1long = scoped!C1long(3, var); + assert(var == 6); auto c2long = scoped!C2long(); assert(cast(size_t)&c1long.l % longAlignment == 0); assert(cast(size_t)&c2long.l % longAlignment == 0); From d038acb44356e364a4ba041da167b0f5b8d0f4dc Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 28 Oct 2012 13:04:48 +0400 Subject: [PATCH 19/27] Workaround for an issue on Posix that fails b3d3c44cc1e879b6ca6850abf94df5ffb6fc37b0 with the following linker error: generated/linux/debug/32/unittest/std/typecons.o: In function `_D3std8typecons51__T6scopedTC3std8typecons18__unittestL3287_53FZv1AZ6scopedFZS3std8typecons51__T6scopedTC3std8typecons18__unittestL3287_53FZv1AZ6scoped51__T6ScopedTC3std8typecons18__unittestL3287_53FZv1AZ6Scoped51__T6ScopedTC3std8typecons18__unittestL3287_53FZv1AZ6Scoped14Scoped_payloadMNgFNdZNgC3std8typecons18__unittestL3287_53FZv1A': /home/braddr/sandbox/d/d-tester/client/pull-346162/phobos/std/typecons.d:3090: undefined reference to `_D3std8typecons51__T6scopedTC3std8typecons18__unittestL3287_53FZv1AZ6scopedFZS3std8typecons51__T6scopedTC3std8typecons18__unittestL3287_53FZv1AZ6scoped51__T6ScopedTC3std8typecons18__unittestL3287_53FZv1AZ6Scoped7alignedFkZk' --- std/typecons.d | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index f9e1414307a..927d1a8d25d 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3076,12 +3076,7 @@ unittest // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for // small objects). We will just use the maximum of filed alignments. alias classInstanceAlignment!T alignment; - - static size_t aligned(size_t n) - { - enum badEnd = alignment - 1; // 0b11, 0b111, ... - return (n + badEnd) & ~badEnd; - } + alias _aligned!alignment aligned; static struct Scoped(T) { @@ -3112,6 +3107,12 @@ unittest return result; } +private size_t _aligned(size_t alignment)(size_t n) +{ + enum badEnd = alignment - 1; // 0b11, 0b111, ... + return (n + badEnd) & ~badEnd; +} + unittest // Issue 6580 testcase { enum alignment = (void*).alignof; From 0511b07cfa9b02b79cca1379f9da9eb1caa5913d Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 4 Nov 2012 00:30:52 +0400 Subject: [PATCH 20/27] Fix typo in ddoc comment --- std/traits.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/traits.d b/std/traits.d index edbd6f29a07..5a76fde0f31 100644 --- a/std/traits.d +++ b/std/traits.d @@ -2798,7 +2798,7 @@ Example: class A { byte b; } class B { long l; } -// As class instancec always has a hidden pointer +// As class instance always has a hidden pointer static assert(classInstanceAlignment!A == (void*).alignof); static assert(classInstanceAlignment!B == long.alignof); --- From 525fb51c87fcc8bea8e117ae91f978415059126b Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 4 Nov 2012 00:34:27 +0400 Subject: [PATCH 21/27] Prefix `EmplaceTest{Struct|Class}` with `__conv_` to avoid possible name clashes * also make it `private` --- std/conv.d | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/std/conv.d b/std/conv.d index fab35aa214e..9d10f44a21a 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3417,7 +3417,7 @@ T* emplace(T)(T* chunk) return chunk; } -version(unittest) struct EmplaceTest +version(unittest) private struct __conv_EmplaceTest { int i = 3; this(int i) @@ -3438,7 +3438,7 @@ version(unittest) struct EmplaceTest void opAssign(); } -version(unittest) class EmplaceTestClass +version(unittest) private class __conv_EmplaceTestClass { int i = 3; this(int i) @@ -3577,7 +3577,7 @@ unittest unittest { - EmplaceTest k = void; + __conv_EmplaceTest k = void; emplace(&k, 5); assert(k.i == 5); } @@ -3585,7 +3585,7 @@ unittest unittest { int var = 6; - EmplaceTest k = void; + __conv_EmplaceTest k = void; emplace(&k, 5, var); assert(k.i == 5); assert(var == 7); @@ -3675,7 +3675,7 @@ T emplace(T, Args...)(void[] chunk, auto ref Args args) if (is(T == class)) unittest { int var = 6; - auto k = emplace!EmplaceTestClass(new void[__traits(classInstanceSize, EmplaceTestClass)], 5, var); + auto k = emplace!__conv_EmplaceTestClass(new void[__traits(classInstanceSize, __conv_EmplaceTestClass)], 5, var); assert(k.i == 5); assert(var == 7); } @@ -3716,7 +3716,7 @@ unittest unittest { int var = 6; - auto k = emplace!EmplaceTest(new void[EmplaceTest.sizeof], 5, var); + auto k = emplace!__conv_EmplaceTest(new void[__conv_EmplaceTest.sizeof], 5, var); assert(k.i == 5); assert(var == 7); } From 603d2e22f3d5ece339faea9f526975bb5e4d821a Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 18 Nov 2012 20:36:51 +0400 Subject: [PATCH 22/27] Rename private `std.typecons._aligned` to `_alignUp` and add constraint. --- std/typecons.d | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 927d1a8d25d..6f4d32eefd6 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3076,7 +3076,7 @@ unittest // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for // small objects). We will just use the maximum of filed alignments. alias classInstanceAlignment!T alignment; - alias _aligned!alignment aligned; + alias _alignUp!alignment aligned; static struct Scoped(T) { @@ -3107,7 +3107,8 @@ unittest return result; } -private size_t _aligned(size_t alignment)(size_t n) +private size_t _alignUp(size_t alignment)(size_t n) + if(alignment > 0 && !((alignment - 1) & alignment)) { enum badEnd = alignment - 1; // 0b11, 0b111, ... return (n + badEnd) & ~badEnd; From c31fcdcea029e5d88a667e2c8cff65b087085334 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 18 Nov 2012 20:52:41 +0400 Subject: [PATCH 23/27] Remove explicit `emplace` specialization in unittest. --- std/conv.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/conv.d b/std/conv.d index 9d10f44a21a..ef0e4e6b1c1 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3467,11 +3467,11 @@ unittest class K : I {} K k = void; - emplace!K(&k); + emplace(&k); assert(k is null); I i = void; - emplace!I(&i); + emplace(&i); assert(i is null); } From 44ac2b77744e0eb18498d2f9ae387ca87e2a185b Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 18 Nov 2012 20:54:59 +0400 Subject: [PATCH 24/27] Don't use `l` as symbol name. --- std/typecons.d | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 6f4d32eefd6..13e13b0786c 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3132,11 +3132,11 @@ unittest // Issue 6580 testcase enum longAlignment = long.alignof; static class C1long { - long l; byte b = 4; + long long_; byte byte_ = 4; this() { } - this(long _l, ref int i) { l = _l; ++i; } + this(long _long, ref int i) { long_ = _long; ++i; } } - static class C2long { byte[2] b = [5, 6]; long l = 7; } + static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; } static assert(scoped!C1long().sizeof % longAlignment == 0); static assert(scoped!C2long().sizeof % longAlignment == 0); @@ -3146,10 +3146,10 @@ unittest // Issue 6580 testcase auto c1long = scoped!C1long(3, var); assert(var == 6); auto c2long = scoped!C2long(); - assert(cast(size_t)&c1long.l % longAlignment == 0); - assert(cast(size_t)&c2long.l % longAlignment == 0); - assert(c1long.l == 3 && c1long.b == 4); - assert(c2long.b == [5, 6] && c2long.l == 7); + assert(cast(size_t)&c1long.long_ % longAlignment == 0); + assert(cast(size_t)&c2long.long_ % longAlignment == 0); + assert(c1long.long_ == 3 && c1long.byte_ == 4); + assert(c2long.byte_ == [5, 6] && c2long.long_ == 7); } alignmentTest(); From 44310012fea6751561a852cc5ef4056a0ba9d272 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Sun, 18 Nov 2012 21:04:47 +0400 Subject: [PATCH 25/27] Add note about Issue 8902 workaround * Issue 8902 URL: http://d.puremagic.com/issues/show_bug.cgi?id=8902 --- std/conv.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/conv.d b/std/conv.d index ef0e4e6b1c1..5e21cef6876 100644 --- a/std/conv.d +++ b/std/conv.d @@ -3405,7 +3405,7 @@ as $(D chunk)). T* emplace(T)(T* chunk) if (!is(T == class)) { - static T i; + static T i; // Can't use `= T.init` here because of @@@BUG8902@@@. memcpy(chunk, &i, T.sizeof); return chunk; } From e541499ea7bb0a801c7be0e4dfdb96f0df8f6c39 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Mon, 19 Nov 2012 23:09:25 +0400 Subject: [PATCH 26/27] Add comments to `std.typecons.Scoped` implementation --- std/typecons.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/typecons.d b/std/typecons.d index 13e13b0786c..6e76d203856 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3080,10 +3080,13 @@ unittest static struct Scoped(T) { + // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory. private void[aligned(__traits(classInstanceSize, T)) + alignment] Scoped_store = void; @property inout(T) Scoped_payload() inout { + // FIXME: It's assumed here `Scoped` will not be arbitrarily moved in memory. + // ("arbitrarily" means an unaligned move) return cast(inout(T)) cast(void*) aligned(cast(size_t) Scoped_store.ptr); } alias Scoped_payload this; From 1450381ba6837956e1aa0fcef45e7e5d468b07a1 Mon Sep 17 00:00:00 2001 From: Denis Shelomovskij Date: Mon, 19 Nov 2012 23:47:23 +0400 Subject: [PATCH 27/27] Add workaround for unaligned `Scoped` movement in memory * class instance now moved accordingly --- std/typecons.d | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 6e76d203856..d275acbeef3 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3081,13 +3081,21 @@ unittest static struct Scoped(T) { // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory. - private void[aligned(__traits(classInstanceSize, T)) + alignment] Scoped_store = void; + private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void; @property inout(T) Scoped_payload() inout { - // FIXME: It's assumed here `Scoped` will not be arbitrarily moved in memory. - // ("arbitrarily" means an unaligned move) - return cast(inout(T)) cast(void*) aligned(cast(size_t) Scoped_store.ptr); + void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr); + // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly. + immutable size_t d = alignedStore - Scoped_store.ptr; + size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof]; + if(d != *currD) + { + import core.stdc.string; + memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T)); + *currD = d; + } + return cast(inout(T)) alignedStore; } alias Scoped_payload this; @@ -3106,7 +3114,8 @@ unittest Scoped!T result; immutable size_t d = cast(void*) result.Scoped_payload - result.Scoped_store.ptr; - emplace!(Unqual!T)(result.Scoped_store[d .. $], args); + *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d; + emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], args); return result; }