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 }