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 48 import std.traits : isIntegral; 49 BigEndian!T opAssign(U)(U val) if(!is(U.isBigEndian) && isIntegral!U) { 50 assert(val <= T.max && val >= T.min); 51 this.asNative = swapIfNeeded(cast(T)val); 52 return this; 53 } 54 55 BigEndian!T opAssign(U)(U val) if(is(U : const ubyte[])) { 56 this = BigEndian!T(val); 57 return this; 58 } 59 60 static U swapIfNeeded (U)(U val) { 61 import std.bitmanip:swapEndian; 62 63 version(BigEndian) { 64 return val; 65 } else { 66 static if (is(U.isBigEndian)) { 67 return val; 68 } else { 69 enum _2066_cannot_handle_swapEndian = false; 70 static if (_2066_cannot_handle_swapEndian) { 71 static if (U.sizeof == 8) { 72 return (((val & 0x00000000000000ffUL) << 56UL) | 73 ((val & 0x000000000000ff00UL) << 40UL) | 74 ((val & 0x0000000000ff0000UL) << 24UL) | 75 ((val & 0x00000000ff000000UL) << 8UL) | 76 ((val & 0x000000ff00000000UL) >> 8UL) | 77 ((val & 0x0000ff0000000000UL) >> 24UL) | 78 ((val & 0x00ff000000000000UL) >> 40UL) | 79 ((val & 0xff00000000000000UL) >> 56UL) 80 ); 81 } else static if (U.sizeof == 4) { 82 return ((val & 0x000000ff) << 24) | 83 ((val & 0x0000ff00) << 8) | 84 ((val & 0x00ff0000) >> 8) | 85 ((val & 0xff000000) >> 24); 86 } else static if (U.sizeof == 2) { 87 return cast(ushort)(((val & 0xff00) >> 8) | 88 ((val & 0x00ff) << 8)); 89 } else static if (U.sizeof == 1) { 90 assert(0, "you should not use BigEndian for byte-sized vaules"); 91 } else { 92 assert(0, "cannot swap this byteSize"); 93 } 94 } else { 95 return swapEndian(val); 96 } 97 } 98 } 99 } 100 101 version(BigEndian) {} else { 102 static assert(swapIfNeeded(0xABCD_EF01_2345_6789) == 0x8967_4523_01EF_CDAB); 103 static assert(swapIfNeeded(0x0123_4567_89AB_CDEF) == 0xEFCD_AB89_6745_2301); 104 } 105 } 106 107 auto bigEndian(T)(T val) pure { 108 static if (is(T.isBigEndian)) { 109 return BigEndian!(typeof(val.asNative))(val.asNative); 110 } else { 111 return BigEndian!T(val); 112 } 113 } 114 115 T[] toArray(T)(const ubyte[] _array, const size_t size) { 116 if (__ctfe) { 117 T[] result; 118 alias sliceType = typeof(_array[0 .. T.sizeof]); 119 120 result.length = size; 121 122 foreach(i; 0 .. size) { 123 const pos = i * T.sizeof; 124 static if (is(typeof(T(sliceType.init)))) { 125 result[i] = T(_array[pos .. pos + T.sizeof]); 126 } else { 127 static assert(0, T.stringof ~ " has to have a constructor taking " ~ sliceType.stringof); 128 } 129 } 130 131 return result; 132 } else { 133 return cast(T[])(_array); 134 } 135 } 136 137 T fromArray(T)(const ubyte[] _array) { 138 if (__ctfe) { 139 uint offset; 140 T result; 141 static assert(T.alignof == 1, "Be sure to use this only on align(1) structures!"); 142 assert(_array.length >= T.sizeof, "your input array needs to be at least as long as your type.sizeof"); 143 144 ///XXX this cucially depends on your type being byte aligned! 145 foreach (member; __traits(derivedMembers, struct_type)) { 146 alias type = typeof(__traits(getMember, instance, member)); 147 148 static if (!(is(type == function) || is(type == const))) { 149 alias sliceType = typeof(_array[0 .. type.sizeof]); 150 static if (is(typeof(type(sliceType.init)))) { 151 __traits(getMember, result, member) = type(_array[offset .. offset + type.sizeof]); 152 } else static if (type.sizeof == sliceType.init[0].sizeof && is(typeof(cast(type)(sliceType.init[0])))) { 153 __traits(getMember, result, member) = type(_array[offset .. offset + type.sizeof][0]); 154 } else { 155 static assert(0, T.stringof ~ " has to have a constructor taking or needs to be castable to ubyte" ~ sliceType.stringof); 156 } 157 offset += type.sizeof; 158 assert(__traits(getMember, result, member).alignof == offset); 159 } 160 } 161 162 return result; 163 } else { 164 return *(cast(T*) _array.ptr); 165 } 166 } 167 168 uint sizeInBytes(ulong val) pure @nogc nothrow { 169 foreach(n;0 .. cast(uint)ulong.sizeof) { 170 if (!(val >>= 8)) { 171 return n+1; 172 } else { 173 continue; 174 } 175 } 176 assert(0); 177 } 178 import std.range : isRandomAccessRange, ElementType; 179 180 struct SkipArray(T) if (isRandomAccessRange!(ElementType!T)) { 181 const(ElementType!T)[] arrays; 182 size_t _length; 183 184 @property const(size_t) length() const pure { 185 return cast(const) _length; 186 } 187 188 auto opOpAssign (string op)(const T rhs) { 189 static if (op == "~") { 190 arrays ~= rhs; 191 _length += rhs.length; 192 } else { 193 assert(0, "Operator " ~ op ~ " not supported"); 194 } 195 } 196 197 const auto opIndex(const size_t idx) { 198 assert(idx < length); 199 size_t currentPos; 200 foreach(ref a;arrays) { 201 if (idx >= a.length + currentPos) { 202 currentPos += a.length; 203 } else { 204 return a[idx - currentPos]; 205 } 206 } 207 assert(0, "invalid idx"); 208 } 209 210 this(T arrays) { 211 this.arrays = arrays; 212 foreach(a;arrays) { 213 _length += a.length; 214 } 215 } 216 } 217 218 auto skipArray(T)(T t) { 219 return SkipArray!T(t); 220 } 221 222 static immutable intArrArr = skipArray([[1,2],[3],[4,5,6],[7,8,9]]); 223 static assert(intArrArr.length == 9); 224 static assert(intArrArr[3] == 4); 225 static assert(intArrArr[8] == 9); 226 static assert(intArrArr[0] == 1); 227 228 unittest { 229 auto arr = skipArray([["Hello"]]); 230 arr ~= [["beautiful"], ["world"]]; 231 assert(arr.length == 3); 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 }