1 module tardy.allocators;
2 
3 
4 import tardy.from;
5 
6 
7 template SBOAllocator(size_t N) {
8     import std.experimental.allocator.building_blocks.fallback_allocator: FallbackAllocator;
9     import std.experimental.allocator.mallocator: Mallocator;
10 
11     alias SBOAllocator = FallbackAllocator!(
12         InSitu!N,
13         Mallocator,
14     );
15 }
16 
17 
18 struct InSitu(size_t N) {
19 
20     import std.experimental.allocator: platformAlignment;
21 
22     enum alignment = platformAlignment;
23     static assert(N >= alignment);
24 
25     union {
26         private ubyte[N] _buffer;
27         private double _forAlignmentOnly_;
28     }
29 
30     @disable this(this);
31 
32     void[] allocate(size_t n) return scope {
33         return _buffer[0 .. n];
34     }
35 
36     bool deallocate(scope void[] buf) const {
37         import std.typecons: Ternary;
38         import std.traits: functionAttributes, FA = FunctionAttribute;
39 
40         static impl() {
41             throw new Exception("Not my buffer");
42         }
43 
44         if(owns(buf) == Ternary.no) {
45             static if(functionAttributes!impl & FA.nogc)
46                 impl;
47             else
48                 assert(false, "Not my buffer");
49         }
50 
51         return true;
52     }
53 
54     auto owns(scope void[] buf) const {
55         import std.typecons: Ternary;
56         return buf.ptr is _buffer.ptr
57             ? Ternary.yes
58             : Ternary.no;
59     }
60 }
61 
62 
63 struct GC {
64 
65     import std.experimental.allocator.gc_allocator: GCAllocator;
66 
67     enum alignment = GCAllocator.alignment;
68 
69     static GC instance;
70 
71     void[] allocate(size_t n) @safe return scope pure nothrow {
72         return GCAllocator.instance.allocate(n);
73     }
74 
75     bool deallocate(scope void[]) @safe scope pure nothrow @nogc const {
76         // By never deallocating, all operations using this allocator can
77         // be @trusted
78         return true;
79     }
80 
81 }