1 /** 2 Miscelleanous functions that assist in type conversions. 3 */ 4 module xlld.conv.misc; 5 6 import xlld.from; 7 8 /// 9 template isUserStruct(T) { 10 import xlld.any: Any; 11 import xlld.sdk.xlcall: XLOPER12; 12 import std.datetime: DateTime; 13 import std.typecons: Tuple; 14 import std.traits: Unqual; 15 import std.range.primitives: isInputRange; 16 17 enum isUserStruct = 18 is(T == struct) 19 && !is(Unqual!T == Any) 20 && !is(Unqual!T == DateTime) 21 && !is(Unqual!T: Tuple!A, A...) 22 && !is(Unqual!T == XLOPER12) 23 && !isVector!T 24 && !isInputRange!T 25 ; 26 } 27 28 template isVector(T) { 29 version(Have_automem) { 30 import automem.vector: Vector; 31 import std.traits: Unqual; 32 enum isVector = is(Unqual!T == Vector!(E, A), E, A); 33 } else 34 enum isVector = false; 35 } 36 37 38 template isSomeString(T) { 39 import std.traits: isSomeString_ = isSomeString, Unqual; 40 enum isSomeString = 41 isSomeString_!T 42 || (isVector!T && is(Unqual!(typeof(T.init[0])) == char)) 43 ; 44 } 45 46 47 template isTuple(T) { 48 import std.typecons: Tuple; 49 import std.traits: Unqual; 50 enum isTuple = is(Unqual!T: Tuple!A, A...); 51 } 52 53 54 template isSequence(T) { 55 import std.traits: isArray; 56 enum isSequence = isArray!T || isTuple!T || isVector!T; 57 } 58 59 /// 60 __gshared immutable gDupMemoryException = new Exception("Failed to allocate memory in dup"); 61 62 63 /** 64 Deep copy of an oper 65 */ 66 from!"xlld.sdk.xlcall".XLOPER12 dup(A)(from!"xlld.sdk.xlcall".XLOPER12 oper, ref A allocator) @safe { 67 68 import xlld.sdk.xlcall: XLOPER12, XlType; 69 import std.experimental.allocator: makeArray; 70 71 XLOPER12 ret; 72 73 ret.xltype = oper.xltype; 74 75 switch(stripMemoryBitmask(oper.xltype)) with(XlType) { 76 77 default: 78 ret = oper; 79 return ret; 80 81 case xltypeStr: 82 const length = operStringLength(oper) + 1; 83 84 () @trusted { 85 ret.val.str = allocator.makeArray!wchar(length).ptr; 86 if(ret.val.str is null) 87 throw gDupMemoryException; 88 }(); 89 90 () @trusted { ret.val.str[0 .. length] = oper.val.str[0 .. length]; }(); 91 return ret; 92 93 case xltypeMulti: 94 () @trusted { 95 ret.val.array.rows = oper.val.array.rows; 96 ret.val.array.columns = oper.val.array.columns; 97 const length = oper.val.array.rows * oper.val.array.columns; 98 ret.val.array.lparray = allocator.makeArray!XLOPER12(length).ptr; 99 100 if(ret.val.array.lparray is null) 101 throw gDupMemoryException; 102 103 foreach(i; 0 .. length) { 104 ret.val.array.lparray[i] = oper.val.array.lparray[i].dup(allocator); 105 } 106 }(); 107 108 return ret; 109 } 110 111 assert(0); 112 } 113 114 115 116 from!"xlld.sdk.xlcall".XlType stripMemoryBitmask(in from!"xlld.sdk.xlcall".XlType type) @safe @nogc pure nothrow { 117 import xlld.sdk.xlcall: XlType, xlbitXLFree, xlbitDLLFree; 118 return cast(XlType)(type & ~(xlbitXLFree | xlbitDLLFree)); 119 } 120 121 /// 122 ushort operStringLength(T)(in T value) { 123 import xlld.sdk.xlcall: XlType; 124 import nogc.exception: enforce; 125 126 enforce(value.xltype.stripMemoryBitmask == XlType.xltypeStr, 127 "Cannot calculate string length for oper of type ", cast(int) value.xltype); 128 129 return cast(ushort) value.val.str[0]; 130 } 131 132 133 // can't be pure because to!double isn't pure 134 string toString(in from!"xlld.sdk.xlcall".XLOPER12 oper) @safe { 135 import xlld.sdk.xlcall: XlType; 136 import xlld.conv.misc: stripMemoryBitmask; 137 import std.conv: text; 138 import std.format: format; 139 140 string ret; 141 142 ret ~= "XLOPER12("; 143 switch(stripMemoryBitmask(oper.xltype)) { 144 default: 145 ret ~= oper.xltype.stripMemoryBitmask.text; 146 break; 147 148 case XlType.xltypeSRef: 149 import xlld.func.xl: Coerced; 150 auto coerced = () @trusted { return Coerced(&oper); }(); 151 return "SRef[ " ~ coerced.toString ~ " ]"; 152 153 case XlType.xltypeNum: 154 ret ~= format!"%.6f"(oper.val.num); 155 break; 156 157 case XlType.xltypeStr: 158 ret ~= `"`; 159 () @trusted { 160 const ulong length = oper.val.str[0]; 161 ret ~= text(oper.val.str[1 .. 1 + length]); 162 }(); 163 ret ~= `"`; 164 break; 165 166 case XlType.xltypeInt: 167 ret ~= text(oper.val.w); 168 break; 169 170 case XlType.xltypeBool: 171 ret ~= text(oper.val.bool_); 172 break; 173 174 case XlType.xltypeErr: 175 ret ~= "ERROR"; 176 break; 177 178 case XlType.xltypeBigData: 179 () @trusted { 180 ret ~= "BIG("; 181 ret ~= text(oper.val.bigdata.h.hdata); 182 ret ~= ", "; 183 ret ~= text(oper.val.bigdata.cbData); 184 ret ~= ")"; 185 }(); 186 } 187 ret ~= ")"; 188 return ret; 189 } 190 191 /// 192 __gshared immutable multiMemoryException = new Exception("Failed to allocate memory for multi oper"); 193 194 /// Returns an array XLOPER12 195 from!"xlld.sdk.xlcall".XLOPER12 multi(A)(int rows, int cols, ref A allocator) @trusted { 196 import xlld.sdk.xlcall: XLOPER12, XlType; 197 198 auto ret = XLOPER12(); 199 200 ret.xltype = XlType.xltypeMulti; 201 () @trusted { 202 ret.val.array.rows = rows; 203 ret.val.array.columns = cols; 204 }(); 205 206 auto slice = allocator.allocate(rows * cols * ret.sizeof); 207 ret.val.array.lparray = () @trusted { return cast(XLOPER12*) slice.ptr; }(); 208 209 if(ret.val.array.lparray is null) 210 throw multiMemoryException; 211 212 return ret; 213 }