QuantLib::Array operToQlArray(const OPER &xVector, const std::string paramName) { OPER xTemp; bool excelToFree = false; bool xllToFree = false; try { RP_REQUIRE(!(xVector.xltype & xltypeErr), "input value '" << paramName << "' has type=error"); if (xVector.xltype & (xltypeMissing | xltypeNil)) return QuantLib::Array(); const OPER *xMulti; if (xVector.xltype == xltypeMulti) { xMulti = &xVector; } else if (xVector.xltype == xltypeStr) { splitOper(&xVector, &xTemp); xMulti = &xTemp; xllToFree = true; } else { Excel(xlCoerce, &xTemp, 2, &xVector, TempInt(xltypeMulti)); xMulti = &xTemp; excelToFree = true; } int size = xMulti->val.array.rows * xMulti->val.array.columns; QuantLib::Array a(size); for (int i=0; i<size; ++i) { a[i] = reposit::convert2<double>(reposit::ConvertOper(xMulti->val.array.lparray[i])); } if (excelToFree) { Excel(xlFree, 0, 1, &xTemp); } else if (xllToFree) { freeOper(&xTemp); } return a; } catch (const std::exception &e) { if (excelToFree) { Excel(xlFree, 0, 1, &xTemp); } else if (xllToFree) { freeOper(&xTemp); } RP_FAIL("operToVector: error converting parameter '" << paramName << "' : " << e.what()); } }
DLLEXPORT void xlAutoFree(XLOPER *px) { freeOper(px); }
void loop( const boost::shared_ptr<FunctionCall> &functionCall, LoopFunction &loopFunction, OPER *xIn, XLOPER &xOut) { // FIXME - xTemp may not be cleaned up properly in the event of an exception. OPER xTemp, *xMulti; bool excelToFree = false; bool xllToFree = false; // If the input is an array then take its address & carry on if (xIn->xltype == xltypeMulti) { xMulti = xIn; // If the input is a list then call split on it } else if (isList(xIn)) { splitOper(xIn, &xTemp); xMulti = &xTemp; xllToFree = true; // If the input is a scalar then just call the function once & return } else if (xIn->xltype == xltypeNum || xIn->xltype == xltypeBool || xIn->xltype == xltypeStr) { LoopIteration<LoopFunction, InputType, OutputType>()( loopFunction, *xIn, xOut, true); return; // Some other input (e.g. a reference) - try to convert to an array } else { Excel(xlCoerce, &xTemp, 2, xIn, TempInt(xltypeMulti)); xMulti = &xTemp; excelToFree = true; } xOut.val.array.rows = xMulti->val.array.rows; xOut.val.array.columns = xMulti->val.array.columns; int numCells = xMulti->val.array.rows * xMulti->val.array.columns; xOut.val.array.lparray = new XLOPER[numCells]; xOut.xltype = xltypeMulti | xlbitDLLFree; int errorCount = 0; std::ostringstream err; LoopIteration<LoopFunction, InputType, OutputType> loopIteration; for (int i=0; i<numCells; ++i) { try { loopIteration(loopFunction, xMulti->val.array.lparray[i], xOut.val.array.lparray[i], false); } catch (const std::exception &e) { xOut.val.array.lparray[i].xltype = xltypeErr; xOut.val.array.lparray[i].val.err = xlerrNum; if (errorCount > ERROR_LIMIT) { // Limit exceeded. Take no action. For performance reasons we test // this case first since it's most common on big loop w/many errors ; } else if (errorCount < ERROR_LIMIT) { err << std::endl << std::endl << "iteration #" << i << " - " << e.what(); errorCount++; } else { // errorCount == ERROR_LIMIT err << std::endl << std::endl << "iteration #" << i << " - " << e.what() << std::endl << std::endl << "Count of failed iterations in looping function hit " << "limit of " << ERROR_LIMIT + 1 << " - logging discontinued"; errorCount++; } } } if (errorCount) RepositoryXL::instance().logError(err.str(), functionCall); // Free memory if (excelToFree) { Excel(xlFree, 0, 1, &xTemp); } else if (xllToFree) { freeOper(&xTemp); } }