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 // nogc.enforce is @system 127 () @trusted { 128 enforce(value.xltype.stripMemoryBitmask == XlType.xltypeStr, 129 "Cannot calculate string length for oper of type ", cast(int) value.xltype); 130 }(); 131 132 // @trusted because of the `enforce` above 133 return () @trusted { return cast(ushort) value.val.str[0]; }(); 134 } 135 136 137 // can't be pure because to!double isn't pure 138 string toString(in from!"xlld.sdk.xlcall".XLOPER12 oper) @safe { 139 import xlld.sdk.xlcall: XlType; 140 import xlld.conv.misc: stripMemoryBitmask; 141 import std.conv: text; 142 import std.format: format; 143 144 string ret; 145 146 ret ~= "XLOPER12("; 147 switch(stripMemoryBitmask(oper.xltype)) { 148 default: 149 ret ~= oper.xltype.stripMemoryBitmask.text; 150 break; 151 152 case XlType.xltypeSRef: 153 import xlld.func.xl: Coerced; 154 auto coerced = () @trusted { return Coerced(&oper); }(); 155 return "SRef[ " ~ coerced.toString ~ " ]"; 156 157 case XlType.xltypeNum: 158 ret ~= format!"%.6f"(oper.val.num); 159 break; 160 161 case XlType.xltypeStr: 162 ret ~= `"`; 163 () @trusted { 164 const ulong length = oper.val.str[0]; 165 ret ~= text(oper.val.str[1 .. 1 + length]); 166 }(); 167 ret ~= `"`; 168 break; 169 170 case XlType.xltypeInt: 171 ret ~= text(oper.val.w); 172 break; 173 174 case XlType.xltypeBool: 175 ret ~= text(oper.val.bool_); 176 break; 177 178 case XlType.xltypeErr: 179 ret ~= "ERROR"; 180 break; 181 182 case XlType.xltypeBigData: 183 () @trusted { 184 ret ~= "BIG("; 185 ret ~= text(oper.val.bigdata.h.hdata); 186 ret ~= ", "; 187 ret ~= text(oper.val.bigdata.cbData); 188 ret ~= ")"; 189 }(); 190 } 191 ret ~= ")"; 192 return ret; 193 } 194 195 /// 196 __gshared immutable multiMemoryException = new Exception("Failed to allocate memory for multi oper"); 197 198 /// Returns an array XLOPER12 199 from!"xlld.sdk.xlcall".XLOPER12 multi(A)(int rows, int cols, ref A allocator) @trusted { 200 import xlld.sdk.xlcall: XLOPER12, XlType; 201 202 auto ret = XLOPER12(); 203 204 ret.xltype = XlType.xltypeMulti; 205 () @trusted { 206 ret.val.array.rows = rows; 207 ret.val.array.columns = cols; 208 }(); 209 210 auto slice = allocator.allocate(rows * cols * ret.sizeof); 211 ret.val.array.lparray = () @trusted { return cast(XLOPER12*) slice.ptr; }(); 212 213 if(ret.val.array.lparray is null) 214 throw multiMemoryException; 215 216 return ret; 217 }