1 module automem.traits;
2 
3 
4 void checkAllocator(T)() {
5     import std.experimental.allocator: make, dispose;
6     import std.traits: hasMember;
7 
8     static if(hasMember!(T, "instance"))
9         alias allocator = T.instance;
10     else
11         T allocator;
12 
13     int* i = allocator.make!int;
14     allocator.dispose(&i);
15     void[] bytes = allocator.allocate(size_t.init);
16     allocator.deallocate(bytes);
17 }
18 
19 enum isAllocator(T) = is(typeof(checkAllocator!T));
20 
21 
22 @("isAllocator")
23 @safe @nogc pure unittest {
24     import std.experimental.allocator.mallocator: Mallocator;
25     import test_allocator: TestAllocator;
26 
27     static assert( isAllocator!Mallocator);
28     static assert( isAllocator!TestAllocator);
29     static assert(!isAllocator!int);
30 }
31 
32 
33 template isGlobal(Allocator) {
34     enum isGlobal = isSingleton!Allocator || isTheAllocator!Allocator;
35 }
36 
37 template isSingleton(Allocator) {
38     import std.traits: hasMember;
39     enum isSingleton = hasMember!(Allocator, "instance");
40 }
41 
42 template isTheAllocator(Allocator) {
43     import std.experimental.allocator: theAllocator;
44     enum isTheAllocator = is(Allocator == typeof(theAllocator));
45 }
46 
47 /**
48    Determines if a type is Unique.
49  */
50 template isUnique(T) {
51     import automem.unique: Unique;
52     import std.traits: TemplateOf;
53     enum isUnique = __traits(isSame, TemplateOf!T, Unique);
54 }
55 
56 ///
57 @("isUnique")
58 @safe unittest {
59     import automem.unique: Unique;
60 
61     static struct Point {
62         int x;
63         int y;
64     }
65 
66     auto u = Unique!Point(2, 3);
67     static assert(isUnique!(typeof(u)));
68 
69     auto p = Point(2, 3);
70     static assert(!isUnique!(typeof(p)));
71 }
72 
73 /**
74    Determines if a type is RefCounted.
75  */
76 template isRefCounted(T) {
77     import automem.ref_counted: RefCounted;
78     import std.traits: TemplateOf;
79     enum isRefCounted = __traits(isSame, TemplateOf!T, RefCounted);
80 }
81 
82 ///
83 @("isRefCounted")
84 @safe unittest {
85     import automem.ref_counted: RefCounted;
86     
87     static struct Point {
88         int x;
89         int y;
90     }
91 
92     auto s = RefCounted!Point(2, 3);
93     static assert(isRefCounted!(typeof(s)));
94 
95     auto p = Point(2, 3);
96     static assert(!isRefCounted!(typeof(p)));
97 }
98 
99 
100 /**
101    The target of a `Unique` or `RefCounted` pointer.
102  */
103 template PointerTarget(T)
104     if (isUnique!T || isRefCounted!T)
105 {
106     alias PointerTarget = T.Type;
107 }
108 
109 ///
110 @("Get the target of a Unique or RefCounter pointer")
111 @safe unittest {
112     import automem.unique: Unique;
113     import automem.ref_counted: RefCounted;
114 
115     static struct Point {
116         int x;
117         int y;
118     }
119 
120     auto u = Unique!Point(2, 3);
121     static assert(is(Point == PointerTarget!(typeof(u))));
122 
123     auto s = RefCounted!Point(2, 3);
124     static assert(is(Point == PointerTarget!(typeof(s))));
125 }
126 
127 ///
128 @("Mixing Unique and RefCounted pointers")
129 unittest {
130 	import std.math : approxEqual;
131     import automem.unique: Unique;
132     import automem.ref_counted: RefCounted;
133 
134     static struct Point {
135         int x;
136         int y;
137     }
138 
139     static double distance(T, U)(auto ref T p1, auto ref U p2)
140         if (is(PointerTarget!T == Point) && 
141             is(PointerTarget!U == Point))
142     {
143         import std.conv : to;
144         import std.math : sqrt, pow;
145         return((pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2)).to!double.sqrt);
146     }
147 
148     int x1 = 2;
149     int y1 = 3;
150     int x2 = x1 + 3;
151     int y2 = y1 + 4;
152 
153     auto u_p1 = Unique!Point(x1, y1);
154     auto u_p2 = Unique!Point(x2, y2);
155     assert(approxEqual(distance(u_p1, u_p2), 5.0));
156 
157     auto rc_p1 = RefCounted!Point(x1, y1);
158     auto rc_p2 = RefCounted!Point(x2, y2);
159     assert(approxEqual(distance(rc_p1, rc_p2), 5.0));
160 
161     assert(approxEqual(distance(u_p1, rc_p2), 5.0));
162     assert(approxEqual(distance(rc_p1, u_p2), 5.0));
163 }