1 module utils; 2 /*************************** 3 * Utils used by SQLite-D * 4 * By Stefan Koch 2016 * 5 ***************************/ 6 7 // Copyright Stefan Koch 2015 - 2018. 8 // Distributed under the Boost Software License, Version 1.0. 9 // (See accompanying file LICENSE.md or copy at 10 // http://www.boost.org/LICENSE_1_0.txt) 11 12 13 /** this struct tries to keep it's own value as BigEndian */ 14 struct BigEndian(T) { 15 T asNative; 16 alias asBigEndian this; 17 pure nothrow @safe @nogc : 18 @property T asBigEndian() { 19 return swapIfNeeded(asNative); 20 } 21 22 @property asBigEndian(U)(U val) if(is(U == T)) { 23 return asNative = swapIfNeeded(val); 24 } 25 26 alias isBigEndian = void; 27 28 this (T val) { 29 static if (is(T.isBigEndian)) { 30 this.asNative = val.asNative; 31 } else { 32 this.asNative = swapIfNeeded(val); 33 } 34 } 35 36 this(const ubyte[] _array) @trusted { 37 assert(T.sizeof == _array.length); 38 foreach(i;0 .. T.sizeof) { 39 asNative |= (_array[i] << i*8UL); 40 } 41 } 42 43 BigEndian!T opAssign(BigEndian!T val) { 44 this.asNative = val.asNative; 45 return this; 46 } 47 import std.traits : isIntegral; 48 BigEndian!T opAssign(U)(U val) if(!is(U.isBigEndian) && isIntegral!U) { 49 assert(val <= T.max && val >= T.min); 50 this.asNative = swapIfNeeded(cast(T)val); 51 return this; 52 } 53 54 BigEndian!T opAssign(U)(U val) if(is(U : const ubyte[])) { 55 this = BigEndian!T(val); 56 return this; 57 } 58 59 static U swapIfNeeded (U)(U val) { 60 import std.bitmanip:swapEndian; 61 62 version(BigEndian) { 63 return val; 64 } else { 65 static if (is(U.isBigEndian)) { 66 return val; 67 } else { 68 enum _2066_cannot_handle_swapEndian = true; 69 static if (_2066_cannot_handle_swapEndian) { 70 static if (U.sizeof == 8) { 71 return (((val & 0x00000000000000ffUL) << 56UL) | 72 ((val & 0x000000000000ff00UL) << 40UL) | 73 ((val & 0x0000000000ff0000UL) << 24UL) | 74 ((val & 0x00000000ff000000UL) << 8UL) | 75 ((val & 0x000000ff00000000UL) >> 8UL) | 76 ((val & 0x0000ff0000000000UL) >> 24UL) | 77 ((val & 0x00ff000000000000UL) >> 40UL) | 78 ((val & 0xff00000000000000UL) >> 56UL) 79 ); 80 } else static if (U.sizeof == 4) { 81 return ((val & 0x000000ff) << 24) | 82 ((val & 0x0000ff00) << 8) | 83 ((val & 0x00ff0000) >> 8) | 84 ((val & 0xff000000) >> 24); 85 } else static if (U.sizeof == 2) { 86 return cast(ushort)(((val & 0xff00) >> 8) | 87 ((val & 0x00ff) << 8)); 88 } else static if (U.sizeof == 1) { 89 assert(0, "you should not use BigEndian for byte-sized vaules"); 90 } else { 91 assert(0, "cannot swap this byteSize"); 92 } 93 } else { 94 return swapEndian(val); 95 } 96 } 97 } 98 } 99 100 version(BigEndian) {} else { 101 static assert(swapIfNeeded(0xABCD_EF01_2345_6789) == 0x8967_4523_01EF_CDAB); 102 static assert(swapIfNeeded(0x0123_4567_89AB_CDEF) == 0xEFCD_AB89_6745_2301); 103 } 104 } 105 106 auto bigEndian(T)(T val) pure { 107 static if (is(T.isBigEndian)) { 108 return BigEndian!(typeof(val.asNative))(val.asNative); 109 } else { 110 return BigEndian!T(val); 111 } 112 } 113 114 T[] toArray(T)(const ubyte[] _array, const size_t size) { 115 if (__ctfe) { 116 T[] result; 117 alias sliceType = typeof(_array[0 .. T.sizeof]); 118 119 result.length = size; 120 121 foreach(i; 0 .. size) { 122 const pos = i * T.sizeof; 123 static if (is(typeof(T(sliceType.init)))) { 124 result[i] = T(_array[pos .. pos + T.sizeof]); 125 } else { 126 static assert(0, T.stringof ~ " has to have a constructor taking " ~ sliceType.stringof); 127 } 128 } 129 130 return result; 131 } else { 132 return cast(T[])(_array); 133 } 134 } 135 136 T fromArray(T)(const ubyte[] _array) { 137 if (__ctfe) { 138 uint offset; 139 T result; 140 static assert(T.alignof == 1, "Be sure to use this only on align(1) structures!"); 141 assert(_array.length >= T.sizeof, "your input array needs to be at least as long as your type.sizeof"); 142 143 ///XXX this cucially depends on your type being byte aligned! 144 foreach (member; __traits(derivedMembers, struct_type)) { 145 alias type = typeof(__traits(getMember, instance, member)); 146 147 static if (!(is(type == function) || is(type == const))) { 148 alias sliceType = typeof(_array[0 .. type.sizeof]); 149 static if (is(typeof(type(sliceType.init)))) { 150 __traits(getMember, result, member) = type(_array[offset .. offset + type.sizeof]); 151 } else static if (type.sizeof == sliceType.init[0].sizeof && is(typeof(cast(type)(sliceType.init[0])))) { 152 __traits(getMember, result, member) = type(_array[offset .. offset + type.sizeof][0]); 153 } else { 154 static assert(0, T.stringof ~ " has to have a constructor taking or needs to be castable to ubyte" ~ sliceType.stringof); 155 } 156 offset += type.sizeof; 157 assert(__traits(getMember, result, member).alignof == offset); 158 } 159 } 160 161 return result; 162 } else { 163 return *(cast(T*) _array.ptr); 164 } 165 } 166 167 uint sizeInBytes(ulong val) pure @nogc nothrow { 168 foreach(n;0 .. cast(uint)ulong.sizeof) { 169 if (!(val >>= 8)) { 170 return n+1; 171 } else { 172 continue; 173 } 174 } 175 assert(0); 176 } 177 import std.range : isRandomAccessRange, ElementType; 178 179 struct SkipArray(T) if (isRandomAccessRange!(ElementType!T)) { 180 const(ElementType!T)[] arrays; 181 size_t _length; 182 183 @property const(size_t) length() const pure { 184 return cast(const) _length; 185 } 186 187 auto opOpAssign (string op)(const T rhs) { 188 static if (op == "~") { 189 arrays ~= rhs; 190 _length += rhs.length; 191 } else { 192 assert(0, "Operator " ~ op ~ " not supported"); 193 } 194 } 195 196 const auto opIndex(const size_t idx) { 197 assert(idx < length); 198 size_t currentPos; 199 foreach(ref a;arrays) { 200 if (idx >= a.length + currentPos) { 201 currentPos += a.length; 202 } else { 203 return a[idx - currentPos]; 204 } 205 } 206 assert(0, "invalid idx"); 207 } 208 209 this(T arrays) { 210 this.arrays = arrays; 211 foreach(a;arrays) { 212 _length += a.length; 213 } 214 } 215 } 216 217 auto skipArray(T)(T t) { 218 return SkipArray!T(t); 219 } 220 221 static immutable intArrArr = skipArray([[1,2],[3],[4,5,6],[7,8,9]]); 222 static assert(intArrArr.length == 9); 223 static assert(intArrArr[3] == 4); 224 static assert(intArrArr[8] == 9); 225 static assert(intArrArr[0] == 1); 226 227 unittest { 228 auto arr = skipArray([["Hello"]]); 229 arr ~= [["beautiful"], ["world"]]; 230 assert(arr.length == 3); 231 232 } 233 234 //TODO implement this! 235 double float64(const ubyte[] _bytes) { 236 assert(_bytes.length > double.sizeof); 237 enum bias = 1023; 238 enum mantissa_length = 53; 239 enum exponent_length = 11; 240 assert(mantissa_length + exponent_length == 64); 241 double result; 242 243 foreach(i; 0 .. (mantissa_length / 8) + 1) { 244 245 } 246 247 return result; 248 }