1 /*
2 MIT License
3 Copyright (c) 2017 Boris Barboris
4 */
5 
6 module daii.utils;
7 
8 import std.conv: to;
9 import std.experimental.allocator: make, dispose;
10 import std.traits: Unqual, isArray;
11 import std.meta: AliasSeq;
12 
13 
14 template isAllocator(T)
15 {
16     // Credits to atila.
17     // https://github.com/atilaneves/automem/blob/master/source/automem/traits.d
18     private template isAllocatorAlike(T)
19     {
20         enum isAllocatorAlike = is(typeof(()
21             {
22                 T allocator;
23                 int* i = allocator.make!int;
24                 allocator.dispose(i);
25                 void[] bytes = allocator.allocate(size_t.init);
26                 bool res = allocator.deallocate(bytes);
27             }));
28     }
29     enum isAllocator = isAllocatorAlike!(Unqual!T) ||
30         isAllocatorAlike!(shared Unqual!T);
31 }
32 
33 template isStaticAllocator(T)
34     if (isAllocator!T)
35 {
36     static if (is(typeof(T.instance)))
37         enum isStaticAllocator = isAllocator!(typeof(T.instance));
38     else
39         enum isStaticAllocator = false;
40 }
41 
42 unittest
43 {
44     import std.experimental.allocator.showcase: StackFront;
45     import std.experimental.allocator.mallocator: Mallocator;
46 
47     static assert(isAllocator!Mallocator);
48     static assert(isStaticAllocator!Mallocator);
49     static assert(!isAllocator!int);
50     static assert(isAllocator!(StackFront!4096));
51     static assert(!isStaticAllocator!(StackFront!4096));
52 }
53 
54 package string fieldExpand(int count, string arrname)()
55 {
56     string result = "";
57     for (int i = 0; i < count; i++)
58     {
59         string idx_str = to!string(i);
60         result ~= arrname ~ "[" ~ idx_str ~ "] field" ~ idx_str ~ ";";
61     }
62     return result;
63 }
64 
65 package string argsAndFields(uint count1, string G1, uint count2)()
66 {
67     string result = "";
68     for (uint i = 0; i < count1; i++)
69         result ~= G1 ~ "[" ~ to!string(i) ~ "], ";
70     for (uint i = 0; i < count2; i++)
71     {
72         result ~= "this.field" ~ to!string(i);
73         if (i < count2 - 1)
74             result ~= ", ";
75     }
76     return result;
77 }
78 
79 template isFunctionPointerType(T: FT*, FT)
80 {
81     enum isFunctionPointerType = is(FT == function);
82 }
83 
84 unittest
85 {
86     auto p = (){};
87     static assert(isFunctionPointerType!(typeof(p)));
88 }
89 
90 template ReturnType(FuncType: FT*, FT)
91 {
92     static if (is(FT RT == return))
93         alias ReturnType = RT;
94     else
95         static assert(0, "FuncType must be function pointer type");
96 }
97 
98 template ParamTypes(FuncType: FT*, FT)
99 {
100     static if (is(FT Params == function))
101         alias ParamTypes = Params;
102     else
103         static assert(0, "FuncType must be function pointer type");
104 }
105 
106 unittest
107 {
108     auto p = (int x){ return x; };
109     static assert(is(ReturnType!(typeof(p)) == int));
110     static assert(is(ParamTypes!(typeof(p)) == AliasSeq!int));
111 }
112 
113 template Take(int count, T...)
114 {
115     alias Take = T[0 .. count];
116 }
117 
118 unittest
119 {
120     alias res = Take!(2, int, int, int, float);
121     static assert(is(res == AliasSeq!(int, int)));
122     static assert(!is(res == AliasSeq!(int, float)));
123 }
124 
125 template Skip(int count, T...)
126 {
127     alias Skip = T[count .. $];
128 }
129 
130 unittest
131 {
132     alias res = Skip!(1, int, int, int, float);
133     static assert(is(res == AliasSeq!(int, int, float)));
134 }
135 
136 template isClassOrIface(T)
137 {
138     enum isClassOrIface = is(T == class) || is(T == interface);
139 }