1 /** 2 * Utility functions used across the library. 3 * 4 * Copyright: 2017 Netflix, Inc. 5 * License: $(LINK2 http://www.apache.org/licenses/LICENSE-2.0, Apache License Version 2.0) 6 */ 7 module vectorflow.utils; 8 9 private{ 10 import std.ascii : isDigit; 11 import std.random; 12 import std.stdio : stdout; 13 import std.traits : isSomeString; 14 15 extern(C) int isatty(int); 16 } 17 18 /// RNG used across the library 19 auto static RAND_GEN = Xorshift(42); // way faster than Mersenne-Twister 20 21 auto init_matrix_rand(T)(T[][] M, double rand_scale) 22 { 23 foreach(i; 0..M.length) 24 foreach(j; 0..M[i].length) 25 M[i][j] = rand_scale * (2 * uniform01(RAND_GEN) - 1); 26 return M; 27 } 28 29 auto allocate_matrix_zero(T)(ulong num_row, ulong num_col) 30 { 31 T[][] M; 32 M.length = num_row; 33 foreach(i; 0..num_row) 34 { 35 M[i].length = num_col; 36 foreach(j; 0..num_col) 37 M[i][j] = 0; 38 } 39 return M; 40 } 41 42 /** 43 * Fast but unsafe function to parse a string into a long. 44 */ 45 long to_long(T)(in T str) pure 46 if(isSomeString!T) 47 { 48 long val = 0; 49 foreach(c; str) 50 val = 10 * val + (c - '0'); 51 return val; 52 } 53 54 /** 55 * Fast but unsafe function to parse a string into a float. 56 * 57 * If you trust your input, this is much faster than to!float. 58 * Doesn't handle Inf numbers nor Nan, and doesn't throw exceptions. 59 * Adapted from Phobos std.conv source code. See NOTICE for licence details. 60 */ 61 float to_float(T)(in T p) pure 62 if(isSomeString!T) 63 { 64 static immutable real[14] negtab = 65 [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L, 66 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ]; 67 static immutable real[13] postab = 68 [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L, 69 1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ]; 70 71 int ind = 0; 72 ulong len = p.length; 73 74 float ldval = 0.0; 75 char dot = 0; 76 int exp = 0; 77 long msdec = 0, lsdec = 0; 78 ulong msscale = 1; 79 80 char sign = 0; 81 switch (p[ind]) 82 { 83 case '-': 84 sign++; 85 ind++; 86 break; 87 case '+': 88 ind++; 89 break; 90 default: {} 91 } 92 93 while (ind < len) 94 { 95 int i = p[ind]; 96 while (isDigit(i)) 97 { 98 if (msdec < (0x7FFFFFFFFFFFL-10)/10) 99 msdec = msdec * 10 + (i - '0'); 100 else if (msscale < (0xFFFFFFFF-10)/10) 101 { 102 lsdec = lsdec * 10 + (i - '0'); 103 msscale *= 10; 104 } 105 else 106 exp++; 107 108 exp -= dot; 109 ind++; 110 if (ind == len) 111 break; 112 i = p[ind]; 113 } 114 if (i == '.' && !dot) 115 { 116 ind++; 117 dot++; 118 } 119 else 120 break; 121 } 122 if (ind < len && (p[ind] == 'e' || p[ind] == 'E')) 123 { 124 char sexp; 125 int e; 126 127 sexp = 0; 128 ind++; 129 switch (p[ind]) 130 { 131 case '-': sexp++; 132 goto case; 133 case '+': ind++; 134 break; 135 default: {} 136 } 137 e = 0; 138 while (ind < len && isDigit(p[ind])) 139 { 140 if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow 141 { 142 e = e * 10 + p[ind] - '0'; 143 } 144 ind++; 145 } 146 exp += (sexp) ? -e : e; 147 } 148 149 ldval = msdec; 150 if (msscale != 1) 151 ldval = ldval * msscale + lsdec; 152 if (ldval) 153 { 154 uint u = 0; 155 int pow = 4096; 156 157 while (exp > 0) 158 { 159 while (exp >= pow) 160 { 161 ldval *= postab[u]; 162 exp -= pow; 163 } 164 pow >>= 1; 165 u++; 166 } 167 while (exp < 0) 168 { 169 while (exp <= -pow) 170 { 171 ldval *= negtab[u]; 172 exp += pow; 173 } 174 pow >>= 1; 175 u++; 176 } 177 } 178 return (sign) ? -ldval : ldval; 179 } 180 181 182 final class Hasher { 183 // MurmurHash3 was written by Austin Appleby, and is placed in the public 184 // domain. The author hereby disclaims copyright to this source code. 185 // Original C++ source code at: https://code.google.com/p/smhasher/ 186 187 private static uint _rotl32(uint x, int r) pure nothrow @safe 188 { 189 return (x << r) | (x >> (32 - r)); 190 } 191 192 // Finalization mix - force all bits of a hash block to avalanche 193 private static uint fmix32(uint h) pure nothrow @safe 194 { 195 h ^= h >> 16; 196 h *= 0x85ebca6b; 197 h ^= h >> 13; 198 h *= 0xc2b2ae35; 199 h ^= h >> 16; 200 201 return h; 202 } 203 204 public static uint MurmurHash3(T)(in T key, uint seed = 42) pure nothrow 205 if(isSomeString!T) 206 { 207 const ubyte * data = cast(const(ubyte*))key; 208 uint len = cast(uint)key.length; 209 const int nblocks = len / 4; 210 211 uint h1 = seed; 212 213 const uint c1 = 0xcc9e2d51; 214 const uint c2 = 0x1b873593; 215 216 // body 217 const uint * blocks = cast(const (uint *))(data + nblocks*4); 218 219 for(int i = -nblocks; i; i++) 220 { 221 uint k1 = blocks[i]; 222 223 k1 *= c1; 224 k1 = _rotl32(k1,15); 225 k1 *= c2; 226 227 h1 ^= k1; 228 h1 = _rotl32(h1,13); 229 h1 = h1*5+0xe6546b64; 230 } 231 232 // tail 233 const ubyte * tail = cast(const (ubyte*))(data + nblocks*4); 234 235 uint k1 = 0; 236 237 switch(len & 3) 238 { 239 case 3: k1 ^= tail[2] << 16; goto case 2; 240 case 2: k1 ^= tail[1] << 8; goto case 1; 241 case 1: k1 ^= tail[0]; 242 k1 *= c1; 243 k1 = _rotl32(k1,15); 244 k1 *= c2; 245 h1 ^= k1; goto default; 246 default: 247 break; 248 } 249 250 // finalization 251 h1 ^= len; 252 h1 = fmix32(h1); 253 254 return h1; 255 } 256 } 257 258 package static void ct_msg(string msg)() 259 { 260 pragma(msg, "[VECTORFLOW-COMPILE] " ~ msg); 261 } 262 263 package bool isTerminal() 264 { 265 return isatty(stdout.fileno) == 1; 266 } 267 268 package mixin template opCallNew() 269 { 270 static auto opCall(T...)(T args) 271 { 272 return new typeof(this)(args); 273 } 274 }