1 /** Extra traits for `std.experimental.allocator`;
2  */
3 module nxt.allocator_traits;
4 
5 /** Is `true` iff `T` is an allocator, otherwise `false`.
6  *
7  * Only members and `alignment` and `allocate` are required.
8  *
9  * See_Also: https://dlang.org/phobos/std_experimental_allocator_building_blocks.html
10  * See_Also: https://forum.dlang.org/post/uiavxptceyxsjulkxlec@forum.dlang.org
11  */
12 enum isAllocator(T) = (is(typeof(T.allocate(size_t.init)) == void[])
13                        && is(typeof(T.alignment) : size_t) // currently either uint or size_t
14                        // && __traits(compiles, { enum uint _ = T.alignment; })
15 );
16 
17 version(unittest)
18 {
19     import std.experimental.allocator.building_blocks.null_allocator : NullAllocator;
20     import std.experimental.allocator.mallocator : Mallocator;
21     import std.experimental.allocator.gc_allocator : GCAllocator;
22     import std.experimental.allocator.mmap_allocator : MmapAllocator;
23 }
24 
25 version(unittest)
26 {
27     static assert(isAllocator!NullAllocator);
28     static assert(isAllocator!Mallocator);
29     static assert(isAllocator!GCAllocator);
30     static assert(isAllocator!MmapAllocator);
31     static assert(!isAllocator!int);
32 }
33 
34 /** State of allocator.
35  *
36  * State is zero for `Mallocator`, `GCAllocator`, and `MMapAllocator` and
37  * typically non-zero for the other.
38  *
39  * EMSI containers has this state as their first field.
40  *
41  * TODO: Move to Phobos and put beside
42  * std.experimental.allocator.common.stateSize.
43  */
44 mixin template AllocatorState(Allocator) // TODO: add string fieldName parameter
45 if (isAllocator!Allocator)
46 {
47 	private import std.experimental.allocator.common : stateSize;
48 	static if (stateSize!Allocator == 0)
49 		alias allocator = Allocator.instance;
50 	else
51 		Allocator allocator;
52 }
53 
54 version(unittest)
55 {
56     mixin AllocatorState!GCAllocator g;
57     mixin AllocatorState!Mallocator m;
58     mixin AllocatorState!MmapAllocator p;
59 }
60 
61 version(none):
62 
63 /** Is `true` iff `T` is an allocator, otherwise `false`.
64  */
65 template isAllocator1(T)
66 {
67     import std.experimental.allocator : IAllocator, CAllocatorImpl;
68     enum isAllocator1 = __traits(compiles, { IAllocator alloc = new CAllocatorImpl!T; });
69 }
70 
71 version(unittest)
72 {
73     import std.experimental.allocator.mallocator : Mallocator;
74     static assert(isAllocator1!Mallocator);
75     static assert(!isAllocator1!int);
76 }
77 
78 bool isAllocator2(T)() pure {
79 	import std.experimental.allocator : CAllocatorImpl;
80 	return __traits(compiles, { new CAllocatorImpl!T; });
81 }
82 
83 version(unittest)
84 {
85     import std.experimental.allocator.mallocator : Mallocator;
86     static assert(isAllocator2!Mallocator);
87     static assert(!isAllocator2!int);
88 }