Skip to content

Commit b0188dd

Browse files
committed
Make AffixAllocator take into account RCISharedAllocator
1 parent 4549c4b commit b0188dd

File tree

1 file changed

+103
-48
lines changed

1 file changed

+103
-48
lines changed

std/experimental/allocator/building_blocks/affix_allocator.d

Lines changed: 103 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ Suffixes are slower to get at because of alignment rounding, so prefixes should
1818
be preferred. However, small prefixes blunt the alignment so if a large
1919
alignment with a small affix is needed, suffixes should be chosen.
2020
21-
The following methods are defined if `Allocator` defines them, and forward to it: `deallocateAll`, `empty`, `owns`.
21+
The following methods are defined if `Allocator` defines them,
22+
and forwarded to it: `deallocateAll`, `empty`, `owns`.
2223
*/
2324
struct AffixAllocator(Allocator, Prefix, Suffix = void)
2425
{
2526
import std.algorithm.comparison : min;
2627
import std.conv : emplace;
27-
import std.experimental.allocator : RCIAllocator, theAllocator;
28+
import std.experimental.allocator : RCIAllocator, RCISharedAllocator,
29+
theAllocator, processAllocator;
2830
import std.experimental.allocator.common : stateSize, forwardToMember,
2931
roundUpToMultipleOf, alignedAt, alignDownTo, roundUpToMultipleOf,
3032
hasStaticallyKnownAlignment;
@@ -43,7 +45,8 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
4345
"This restriction could be relaxed in the future.");
4446

4547
/**
46-
If `Prefix` is `void`, the alignment is that of the parent. Otherwise, the alignment is the same as the `Prefix`'s alignment.
48+
If `Prefix` is `void`, the alignment is that of the parent.
49+
Otherwise, the alignment is the same as the `Prefix`'s alignment.
4750
*/
4851
static if (hasStaticallyKnownAlignment!Allocator)
4952
{
@@ -60,61 +63,73 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
6063
enum uint alignment = Prefix.alignof;
6164
}
6265

63-
/**
64-
If the parent allocator `Allocator` is stateful, an instance of it is
65-
stored as a member. Otherwise, `AffixAllocator` uses
66-
`Allocator.instance`. In either case, the name `_parent` is uniformly
67-
used for accessing the parent allocator.
68-
*/
69-
static if (stateSize!Allocator)
66+
private template Impl()
7067
{
71-
Allocator _parent;
72-
static if (is(Allocator == RCIAllocator))
68+
static if (stateSize!Allocator)
7369
{
74-
@nogc nothrow pure @safe
75-
Allocator parent()
76-
{
77-
static @nogc nothrow
78-
RCIAllocator wrapAllocatorObject()
79-
{
80-
import std.experimental.allocator.gc_allocator : GCAllocator;
81-
import std.experimental.allocator : allocatorObject;
70+
Allocator _parent;
8271

83-
return allocatorObject(GCAllocator.instance);
84-
}
85-
86-
if (_parent.isNull)
72+
static if (is(Allocator == RCIAllocator) || is(Allocator == RCISharedAllocator))
73+
{
74+
@nogc nothrow pure @safe
75+
Allocator parent()
8776
{
88-
// If the `_parent` allocator is `null` we will assign
89-
// an object that references the GC as the `parent`.
90-
auto fn = (() @trusted =>
91-
cast(RCIAllocator function() @nogc nothrow pure @safe)(&wrapAllocatorObject))();
92-
_parent = fn();
77+
static @nogc nothrow
78+
RCIAllocator wrapAllocatorObject()
79+
{
80+
import std.experimental.allocator.gc_allocator : GCAllocator;
81+
import std.experimental.allocator : allocatorObject;
82+
83+
return allocatorObject(GCAllocator.instance);
84+
}
85+
86+
static @nogc nothrow
87+
RCISharedAllocator wrapProcAllocatorObject()
88+
{
89+
import std.experimental.allocator.gc_allocator : GCAllocator;
90+
import std.experimental.allocator : sharedAllocatorObject;
91+
92+
return sharedAllocatorObject(GCAllocator.instance);
93+
}
94+
95+
if (_parent.isNull)
96+
{
97+
static if (is(Allocator == RCIAllocator))
98+
{
99+
// If the `_parent` allocator is `null` we will assign
100+
// an object that references the GC as the `parent`.
101+
auto fn = (() @trusted =>
102+
cast(RCIAllocator function() @nogc nothrow pure @safe)(&wrapAllocatorObject))();
103+
_parent = fn();
104+
}
105+
else
106+
{
107+
auto fn = (() @trusted =>
108+
cast(RCIAllocator function() @nogc nothrow pure @safe)(&wrapProcAllocatorObject))();
109+
_parent = fn();
110+
}
111+
}
112+
113+
// `RCIAllocator.alignment` currently doesn't have any attributes
114+
// so we must cast; throughout the allocators module, `alignment`
115+
// is defined as an `enum` for the existing allocators.
116+
// `alignment` should always be `@nogc nothrow pure @safe`; once
117+
// this is enforced by the interface we can remove the cast
118+
auto pureAlign = (() @trusted =>
119+
cast(uint delegate() @nogc nothrow pure @safe)(&_parent.alignment))();
120+
assert(alignment <= pureAlign());
121+
return _parent;
93122
}
94-
95-
// `RCIAllocator.alignment` currently doesn't have any attributes
96-
// so we must cast; throughout the allocators module, `alignment`
97-
// is defined as an `enum` for the existing allocators.
98-
// `alignment` should always be `@nogc nothrow pure @safe`; once
99-
// this is enforced by the interface we can remove the cast
100-
auto pureAlign = (() @trusted =>
101-
cast(uint delegate() @nogc nothrow pure @safe)(&_parent.alignment))();
102-
assert(alignment <= pureAlign());
103-
return _parent;
123+
}
124+
else
125+
{
126+
alias parent = _parent;
104127
}
105128
}
106129
else
107130
{
108-
alias parent = _parent;
131+
alias parent = Allocator.instance;
109132
}
110-
}
111-
else
112-
{
113-
alias parent = Allocator.instance;
114-
}
115-
116-
private template Impl()
117-
{
118133

119134
size_t goodAllocSize(size_t s)
120135
{
@@ -323,6 +338,19 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
323338
*/
324339
static AffixAllocator instance;
325340

341+
/**
342+
If the parent allocator `Allocator` is stateful, an instance of it is
343+
stored as a member. If the parent allocator is null instance of
344+
$(REF RCIAllocator, std,experimental,allocator) or
345+
$(REF RCISharedAllocator, std,experimental,allocator) then `AffixAllocator`
346+
will use $(REF GCAllocator, std,experimental,allocator,gc_allocator).
347+
If the parent allocator `Allocator` is stateless, `AffixAllocator` uses
348+
`Allocator.instance`.
349+
In either case, the name `_parent` is uniformly used for accessing the
350+
parent allocator.
351+
*/
352+
Allocator parent();
353+
326354
/**
327355
Affix access functions offering references to the affixes of a
328356
block `b` previously allocated with this allocator. `b` may not be null.
@@ -545,3 +573,30 @@ struct AffixAllocator(Allocator, Prefix, Suffix = void)
545573
static assert(is(typeof(a.allocate) == shared));
546574
assert(buf.length == 10);
547575
}
576+
577+
@system unittest
578+
{
579+
import std.experimental.allocator : RCISharedAllocator;
580+
581+
shared AffixAllocator!(RCISharedAllocator, uint) a;
582+
auto buf = a.allocate(42);
583+
assert(buf.length == 42);
584+
}
585+
586+
@system unittest
587+
{
588+
import std.experimental.allocator.mallocator : Mallocator;
589+
import std.experimental.allocator.building_blocks.stats_collector;
590+
591+
alias SCAlloc = StatsCollector!(Mallocator, Options.bytesUsed);
592+
alias AffixAl = AffixAllocator!(SCAlloc, uint);
593+
594+
AffixAl a;
595+
auto b = a.allocate(42);
596+
assert(b.length == 42);
597+
assert(a.parent.bytesUsed == 42 + uint.sizeof);
598+
assert((() nothrow @nogc => a.reallocate(b, 100))());
599+
assert(b.length == 100);
600+
assert(a.parent.bytesUsed == 100 + uint.sizeof);
601+
assert((() nothrow @nogc => a.deallocate(b))());
602+
}

0 commit comments

Comments
 (0)