Improvements and fixes in affix_allocator; fix in isPowerOf2; fix alignment in scoped_allocator

This commit is contained in:
Andrei Alexandrescu 2015-05-18 22:04:34 -07:00
parent c175553098
commit c00b5885c1
3 changed files with 42 additions and 18 deletions

View file

@ -19,6 +19,7 @@ The following methods are defined if $(D Allocator) defines them, and forward to
struct AffixAllocator(Allocator, Prefix, Suffix = void)
{
import std.conv, std.experimental.allocator.common, std.traits;
import std.algorithm : min;
static assert(
!stateSize!Prefix || Allocator.alignment >= Prefix.alignof,
@ -30,8 +31,9 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
/**
If $(D Prefix) is $(D void), the alignment is that of the parent. Otherwise, the alignment is the same as the $(D Prefix)'s alignment.
*/
enum uint alignment =
stateSize!Prefix ? Prefix.alignof : Allocator.alignment;
enum uint alignment = isPowerOf2(stateSize!Prefix)
? min(stateSize!Prefix, Allocator.alignment)
: (stateSize!Prefix ? Prefix.alignof : Allocator.alignment);
/**
If the parent allocator $(D Allocator) is stateful, an instance of it is
@ -46,11 +48,15 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
{
size_t goodAllocSize(size_t s)
{
return parent.goodAllocSize(actualAllocationSize(s));
auto a = actualAllocationSize(s);
return roundUpToMultipleOf(parent.goodAllocSize(a)
- stateSize!Prefix - stateSize!Suffix,
this.alignment);
}
private size_t actualAllocationSize(size_t s) const
{
assert(s > 0);
static if (!stateSize!Suffix)
{
return s + stateSize!Prefix;
@ -76,10 +82,16 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
auto result = parent.allocate(actualAllocationSize(bytes));
if (result is null) return null;
static if (stateSize!Prefix)
{
assert(result.ptr.alignedAt(Prefix.alignof));
emplace!Prefix(cast(Prefix*)result.ptr);
}
static if (stateSize!Suffix)
emplace!Suffix(
cast(Suffix*)(result.ptr + result.length - Suffix.sizeof));
{
auto suffixP = result.ptr + result.length - Suffix.sizeof;
assert(suffixP.alignedAt(Suffix.alignof));
emplace!Suffix(cast(Suffix*)(suffixP));
}
return result[stateSize!Prefix .. stateSize!Prefix + bytes];
}
@ -88,20 +100,24 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
{
auto result = parent.allocateAll();
if (result is null) return null;
if (result.length < actualAllocationSize(1))
{
deallocate(result);
return null;
}
static if (stateSize!Prefix)
{
assert(result.length > stateSize!Prefix);
if (result.length <= stateSize!Prefix) return null;
emplace!Prefix(cast(Prefix*)result.ptr);
result = result[stateSize!Prefix .. $];
}
static if (stateSize!Suffix)
{
assert(result.length > stateSize!Suffix);
// Ehm, find a properly aligned place for the suffix
auto p = (result.ptr + result.length - stateSize!Suffix)
.alignDownTo(Suffix.alignof);
assert(p > result.ptr);
if (p <= result.ptr) return null;
emplace!Suffix(cast(Suffix*) p);
result = result[0 .. p - result.ptr];
}
@ -130,7 +146,7 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
{
if (!b.ptr)
{
if (delta) b = allocate(delta);
b = allocate(delta);
return b.length == delta;
}
auto t = actualAllocation(b);
@ -158,8 +174,7 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
static if (hasMember!(Allocator, "deallocate"))
void deallocate(void[] b)
{
auto p = b.ptr - stateSize!Prefix;
parent.deallocate(p[0 .. actualAllocationSize(b.length)]);
if (b.ptr) parent.deallocate(actualAllocation(b));
}
/* The following methods are defined if $(D ParentAllocator) defines
@ -174,13 +189,16 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
static if (stateSize!Prefix)
static ref Prefix prefix(void[] b)
{
assert(b.ptr && b.ptr.alignedAt(Prefix.alignof));
return (cast(Prefix*)b.ptr)[-1];
}
static if (stateSize!Suffix)
ref Suffix suffix(void[] b)
{
assert(b.ptr);
auto p = b.ptr - stateSize!Prefix
+ actualAllocationSize(b.length);
assert(p && p.alignedAt(Suffix.alignof));
return (cast(Suffix*) p)[-1];
}
@ -272,14 +290,11 @@ unittest
unittest
{
import std.experimental.allocator.mallocator;
import std.experimental.allocator.heap_block;
import std.experimental.allocator.common;
//testAllocator!(() => AffixAllocator!(Mallocator, size_t, size_t).it);
testAllocator!({
auto hb = HeapBlock!128(new void[128 * 4096]);
AffixAllocator!(HeapBlock!128, size_t, size_t) a;
a.parent = hb;
auto a = AffixAllocator!(HeapBlock!128, ulong, ulong)
(HeapBlock!128(new void[128 * 4096]));
return a;
});
}

View file

@ -324,7 +324,12 @@ void* alignUpTo(void* ptr, uint alignment)
package bool isPowerOf2(uint x)
{
return (x & (x - 1)) == 0;
return (x & (x - 1)) == 0 && x;
}
unittest
{
assert(!isPowerOf2(0));
}
package bool isGoodStaticAlignment(uint x)
@ -422,14 +427,18 @@ package string forwardToMember(string member, string[] funs...)
package void testAllocator(alias make)()
{
import std.conv : text;
import std.stdio : writeln, stderr;
alias A = typeof(make());
scope(failure) stderr.writeln("testAllocator failed for ", A.stringof);
auto a = make();
// Test alignment
static assert(A.alignment.isPowerOf2);
// Test goodAllocSize
assert(a.goodAllocSize(1) >= A.alignment);
assert(a.goodAllocSize(1) >= A.alignment,
text(a.goodAllocSize(1), " < ", A.alignment));
assert(a.goodAllocSize(11) >= 11.roundUpToMultipleOf(A.alignment));
assert(a.goodAllocSize(111) >= 111.roundUpToMultipleOf(A.alignment));

View file

@ -64,7 +64,7 @@ struct ScopedAllocator(ParentAllocator)
}
/// Alignment offered
enum alignment = ParentAllocator.alignment;
enum alignment = Allocator.alignment;
/**
Forwards to $(D parent.goodAllocSize) (which accounts for the management