1 module gbaid.util;
2 
3 import core.time : Duration, MonoTime, hnsecs;
4 import core.thread : Thread;
5 
6 import std.meta : Alias, AliasSeq, staticIndexOf;
7 import std.path : expandTilde, absolutePath, buildNormalizedPath;
8 import std.conv : to;
9 
10 public enum uint BYTES_PER_KIB = 1024;
11 public enum uint BYTES_PER_MIB = BYTES_PER_KIB * BYTES_PER_KIB;
12 
13 public alias Int8to32Types = AliasSeq!(byte, ubyte, short, ushort, int, uint);
14 public alias IsInt8to32Type(T) = Alias!(staticIndexOf!(T, Int8to32Types) >= 0);
15 
16 public template IntSizeLog2(T) {
17     static if (is(T == byte) || is(T == ubyte)) {
18         private alias IntSizeLog2 = Alias!0;
19     } else static if (is(T == short) || is(T == ushort)) {
20         private alias IntSizeLog2 = Alias!1;
21     } else static if (is(T == int) || is(T == uint)) {
22         private alias IntSizeLog2 = Alias!2;
23     } else static if (is(T == long) || is(T == ulong)) {
24         private alias IntSizeLog2 = Alias!3;
25     } else {
26         static assert (0, "Not an integer type");
27     }
28 }
29 
30 public alias IntAlignMask(T) = Alias!(~((1 << IntSizeLog2!T) - 1));
31 
32 public uint ucast(byte v) {
33     return cast(uint) v & 0xFF;
34 }
35 
36 public uint ucast(short v) {
37     return cast(uint) v & 0xFFFF;
38 }
39 
40 public ulong ucast(int v) {
41     return cast(ulong) v & 0xFFFFFFFF;
42 }
43 
44 public bool checkBit(int i, int b) {
45     return cast(bool) getBit(i, b);
46 }
47 
48 public int getBit(int i, int b) {
49     return i >> b & 1;
50 }
51 
52 public void setBit(ref int i, int b, int n) {
53     i = i & ~(1 << b) | (n & 1) << b;
54 }
55 
56 public int getBits(int i, int a, int b) {
57     return i >> a & (1 << b - a + 1) - 1;
58 }
59 
60 public void setBits(ref int i, int a, int b, int n) {
61     int mask = (1 << b - a + 1) - 1 << a;
62     i = i & ~mask | n << a & mask;
63 }
64 
65 public int sign(long v) {
66     if (v == 0) {
67         return 0;
68     }
69     return 1 - (v >>> 62 & 0b10);
70 }
71 
72 public int mirror(byte b) {
73     int bi = b & 0xFF;
74     return bi << 24 | bi << 16 | bi << 8 | bi;
75 }
76 
77 public int mirror(short s) {
78     return s << 16 | s & 0xFFFF;
79 }
80 
81 public int rotateRight(int i, int shift) {
82     return i >>> shift | i << 32 - shift;
83 }
84 
85 int nextPowerOf2(int i) {
86     i--;
87     i |= i >> 1;
88     i |= i >> 2;
89     i |= i >> 4;
90     i |= i >> 8;
91     i |= i >> 16;
92     return i + 1;
93 }
94 
95 public bool carriedAdd(int a, int b, int c) {
96     int negativeA = a >> 31;
97     int negativeB = b >> 31;
98     int negativeC = c >> 31;
99     return negativeA && negativeB || negativeA && !negativeC || negativeB && !negativeC;
100 }
101 
102 public bool overflowedAdd(int a, int b, int c) {
103     int negativeA = a >> 31;
104     int negativeB = b >> 31;
105     int negativeC = c >> 31;
106     return negativeA && negativeB && !negativeC || !negativeA && !negativeB && negativeC;
107 }
108 
109 public bool borrowedSub(int a, int b, int c) {
110     int negativeA = a >> 31;
111     int negativeB = b >> 31;
112     int negativeC = c >> 31;
113     return (!negativeA || negativeB) && (!negativeA || negativeC) && (negativeB || negativeC);
114 }
115 
116 public bool overflowedSub(int a, int b, int c) {
117     int negativeA = a >> 31;
118     int negativeB = b >> 31;
119     int negativeC = c >> 31;
120     return negativeA && !negativeB && !negativeC || !negativeA && negativeB && negativeC;
121 }
122 
123 public T getSafe(T)(T[] array, int index, T def) {
124     if (index < 0 || index >= array.length) {
125         return def;
126     }
127     return array[index];
128 }
129 
130 public void addAll(K, V)(ref V[K] to, V[K] from) {
131     foreach (k; from.byKey()) {
132         to[k] = from[k];
133     }
134 }
135 
136 public void removeAll(K, V)(ref V[K] to, V[K] from) {
137     foreach (k; from.byKey()) {
138         to.remove(k);
139     }
140 }
141 
142 public string toDString(inout(char)[] cs) {
143     return toDString(cs.ptr, cs.length);
144 }
145 
146 public string toDString(inout(char)* cs) {
147     return toDString(cs, size_t.max);
148 }
149 
150 public string toDString(inout(char)* cs, size_t length) {
151     size_t end;
152     foreach (i; 0 .. length) {
153         if (!cs[i]) {
154             end = i;
155             break;
156         }
157     }
158     return cs[0 .. end].idup;
159 }
160 
161 public string expandPath(string relative) {
162     return buildNormalizedPath(absolutePath(expandTilde(relative)));
163 }
164 
165 public mixin template declareFields(T, bool private_, string name, alias init, uint count) if (count > 0) {
166     import std.conv : to;
167     import std.traits : fullyQualifiedName;
168     import std.meta : Alias;
169 
170     alias visibility = Alias!(private_ ? "private" : "public");
171 
172     mixin(visibility ~ " " ~ T.stringof ~ " " ~ name ~ (count - 1).to!string() ~ " = " ~ fullyQualifiedName!init ~ ";");
173 
174     static if (count == 1) {
175         mixin(visibility ~ " alias " ~ name ~ "(uint index) = Alias!(mixin(\"" ~ name ~ "\" ~ index.to!string()));");
176     } else static if (count > 1) {
177         mixin declareFields!(T, private_, name, init, count - 1);
178     }
179 }
180 
181 public class NullPathException : Exception {
182     public this(string type) {
183         super("Path to \"" ~ type ~ "\" file is null");
184     }
185 }
186 
187 public class Timer {
188     private static enum Duration YIELD_TIME = hnsecs(1000);
189     private MonoTime startTime;
190 
191     public void start() {
192         startTime = MonoTime.currTime();
193     }
194 
195     public alias reset = start;
196     public alias restart = start;
197 
198     @property public Duration elapsed() {
199         return MonoTime.currTime() - startTime;
200     }
201 
202     public void waitUntil(Duration time) {
203         Duration duration = time - elapsed - YIELD_TIME;
204         if (!duration.isNegative()) {
205             Thread.sleep(duration);
206         }
207         while (elapsed < time) {
208             Thread.yield();
209         }
210     }
211 }