1 module rcdata.utils; 2 3 import std.ascii; 4 import std.stdio; 5 import std.range; 6 import std.string; 7 import std.algorithm; 8 import std.exception; 9 10 11 /// Write a hexdump for debugging. Writes to stdout. 12 void hexDump(ubyte[] bytes, int perLine = 16) { 13 14 hexDump(stdout, bytes, perLine); 15 16 } 17 18 /// Write a hexdump for debugging. 19 void hexDump(File file, ubyte[] bytes, int perLine = 16) { 20 21 22 file.writefln("%s bytes:", bytes.length); 23 foreach (value; bytes.chunks(perLine)) { 24 25 const byteContent = format!"%(%0.2x %) "(value); 26 27 file.write(leftJustify(byteContent, perLine * 3)); 28 file.writefln!"%(%c%)"(value.map!(a => a.isGraphical ? cast(char) a : '.')); 29 30 } 31 32 } 33 34 /// Stringof improved to better handle callbacks 35 template stringofone(alias symbol) { 36 37 import std.traits; 38 39 enum string name = mixin(__traits(compiles, symbol.stringof) 40 ? q{ symbol.stringof } 41 : q{ __traits(identifier, symbol) }); 42 43 44 static if (__traits(compiles, __traits(getLocation, symbol))) { 45 46 enum stringofone = format!"`%s` at %s:%s"(name, __traits(getLocation, symbol)[0..2]); 47 48 } 49 50 else enum stringofone = name; 51 52 } 53 54 unittest { 55 56 void foo(string x) { } 57 alias bar = (string x) { }; 58 alias baz = (x) { }; 59 60 } 61 62 /// Run a map on a tuple at runtime. 63 auto tupleMap(alias fun, Args...)(Args args) { 64 65 import std.meta, std.typecons; 66 67 auto mapItem(alias symbol)() { 68 69 return fun(symbol); 70 71 } 72 73 return tuple(staticMap!(mapItem, args)); 74 75 } 76 77 /// Base type for all rcdata exceptions. 78 abstract class RCDataException : Exception { 79 80 mixin basicExceptionCtors; 81 82 } 83 84 /// Check if the two objects are equal. Resolve any pointers when comparing. `class`es use regular comparison and 85 /// respects `opEquals`. 86 bool equalPtr(T)(T a, T b) pure @safe 87 out(r) { 88 89 if (!r) { 90 91 import std.stdio; 92 debug writefln!"T %s: %s != %s"(T.stringof, a, b); 93 94 } 95 96 } 97 do { 98 99 import std.sumtype; 100 101 // Pointer 102 static if (is(T == X*, X)) { 103 104 if (a is b) return true; 105 if (a is null || b is null) return false; 106 107 return equalPtr(*a, *b); 108 109 } 110 111 // Array 112 else static if (is(T == X[], X)) { 113 114 return equal!equalPtr(a, b); 115 116 } 117 118 // SumType 119 else static if (isSumType!T) { 120 121 return match!( 122 (suba, subb) { 123 124 static if (is(typeof(suba) == typeof(subb))) { 125 126 return equalPtr(suba, subb); 127 128 } 129 130 else return false; 131 132 } 133 )(a, b); 134 135 } 136 137 // Struct 138 else static if (is(T == struct) && !__traits(hasMember, T, "opEquals")) { 139 140 static foreach (i, Item; T.tupleof) { 141 142 if (!equalPtr(a.tupleof[i], b.tupleof[i])) { 143 144 return false; 145 146 } 147 148 } 149 150 return true; 151 152 } 153 154 // Anything else 155 else return a == b; 156 157 158 }