@@ -18,13 +18,15 @@ Suffixes are slower to get at because of alignment rounding, so prefixes should
1818be preferred. However, small prefixes blunt the alignment so if a large
1919alignment 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 */
2324struct 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