string RepositoryXL::storeObject( const string &objectIDRaw, const shared_ptr<Object> &object, bool overwrite, boost::shared_ptr<ValueObject> valueObject) { shared_ptr<CallingRange> callingRange = getCallingRange(); string objectID = callingRange->initializeID(objectIDRaw); if (objectIDRaw.empty() && valueObject) valueObject->setProperty("OBJECTID", objectID); shared_ptr<ObjectWrapperXL> objectWrapperXL; ObjectMap::const_iterator result = objectMap_.find(objectID); if (result == objectMap_.end()) { objectWrapperXL = shared_ptr<ObjectWrapperXL> ( new ObjectWrapperXL(objectID, object, callingRange)); objectMap_[objectID] = objectWrapperXL; callingRange->registerObject(objectID, objectWrapperXL); } else { objectWrapperXL = boost::static_pointer_cast<ObjectWrapperXL>(result->second); if (objectWrapperXL->callerKey() != callingRange->key()) { OH_REQUIRE(overwrite, "Cannot create object with ID '" << objectID << "' in cell " << callingRange->addressString() << " because an object with that ID already resides in cell " << objectWrapperXL->callerAddress()); objectWrapperXL->resetCaller(callingRange); callingRange->registerObject(objectID, objectWrapperXL); } objectWrapperXL->reset(object); } registerObserver(objectWrapperXL); return objectWrapperXL->idFull(); }
const CurveClass *get(const QuantLib::Extrapolator *extrapolator) const { const CurveClass *ret = dynamic_cast<const CurveClass*>(extrapolator); OH_REQUIRE(ret, "Unable to convert from type " << typeid(extrapolator).name() << " to type " << typeid(CurveClass).name()); return ret; }
shared_ptr<CallingRange> RepositoryXL::getCallingRange() { string callerName = FunctionCall::instance().callerName(); if (callerName == "VBA") { // Called from VBA - check whether the corresponding calling range // object exists and create it if not. RangeMap::const_iterator i = callingRanges_.find(callerName); if (i == callingRanges_.end()) { shared_ptr<CallingRange> callingRange(new CallingRange); callingRanges_[callingRange->key()] = callingRange; return callingRange; } else { return i->second; } // Called from a worksheet formula } else if (callerName.empty()) { // Calling range not yet named - create a new CallingRange object shared_ptr<CallingRange> callingRange(new CallingRange); callingRanges_[callingRange->key()] = callingRange; return callingRange; } else { // Calling range already named - return associated CallingRange object RangeMap::const_iterator i = callingRanges_.find(callerName); OH_REQUIRE(i != callingRanges_.end(), "No calling range named " << callerName); return i->second; } }
std::string CallingRange::getKeyCount() { static const int KEY_BASE = 16; static const double KEY_MAX = pow((double)KEY_BASE, KEY_WIDTH); OH_REQUIRE(keyCount_ < KEY_MAX, "CallingRange::getKeyCount() : max key value exceeded"); std::ostringstream s; s << '_' << std::setw(KEY_WIDTH) << std::setfill('0') << std::setbase(KEY_BASE) << keyCount_++; return s.str(); }
XLL_DEC OPER *ohFilter( OPER *xInput, OPER *flags) { // declare a shared pointer to the Function Call object boost::shared_ptr<ObjectHandler::FunctionCall> functionCall; try { // instantiate the Function Call object functionCall = boost::shared_ptr<ObjectHandler::FunctionCall>( new ObjectHandler::FunctionCall("ohFilter")); // convert input datatypes to C++ datatypes std::vector<bool> flagsCpp = ObjectHandler::operToVector<bool>(*flags, "flags"); const OPER *xMulti; ObjectHandler::Xloper xTemp; if (xInput->xltype == xltypeMulti) { xMulti = xInput; } else { Excel(xlCoerce, &xTemp, 2, xInput, TempInt(xltypeMulti)); xMulti = &xTemp; } int sizeInput = xMulti->val.array.rows * xMulti->val.array.columns; OH_REQUIRE(sizeInput == flagsCpp.size(), "size mismatch between value vector (" << sizeInput << ") and flag vector (" << flagsCpp.size() << ")"); static OPER xRet; xRet.val.array.rows = count(flagsCpp.begin(), flagsCpp.end(), true); xRet.val.array.columns = 1; xRet.val.array.lparray = new OPER[xRet.val.array.rows]; xRet.xltype = xltypeMulti | xlbitDLLFree; int idx = 0; for (int i=0; i<sizeInput; i++) { if (flagsCpp[i]) { operToOper(&xRet.val.array.lparray[idx++], &xMulti->val.array.lparray[i]); } } return &xRet; } catch (const std::exception &e) { ObjectHandler::RepositoryXL::instance().logError(e.what(), functionCall); return 0; } }
std::string CallingRange::initializeID(const std::string &objectID) { static const std::string anonPrefix("obj"); static const std::string ANONPREFIX("OBJ"); if (objectID.empty()) { if (callerType_ == CallerType::Cell) { return anonPrefix + key_; } else { OH_FAIL("Null string specified for object ID"); } } OH_REQUIRE(objectID.find(counterDelimiter, 0) == std::string::npos, objectID << " is an invalid ID: cannot contain " << counterDelimiter); std::string ID = boost::algorithm::to_upper_copy(objectID); OH_REQUIRE(ID.rfind(ANONPREFIX, ANONPREFIX.size() - 1) == std::string::npos, objectID << " is an invalid ID: cannot start with " << anonPrefix); return objectID; }
CallingRange::CallingRange() : updateCount_(0), callerType_(FunctionCall::instance().callerType()) { if (callerType_ == CallerType::Cell) { // name the calling range key_ = getKeyCount(); XLOPER xRet; Excel(xlfSetName, &xRet, 2, TempStrStl(key_), FunctionCall::instance().callerReference()); OH_REQUIRE(xRet.xltype == xltypeBool && xRet.val.boolean, "Error on call to xlfSetName"); } else { key_ = "VBA"; } }
QuantLib::Array operToQlArray(const OPER &xVector, const std::string paramName) { OPER xTemp; bool excelToFree = false; bool xllToFree = false; try { OH_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] = ObjectHandler::convert2<double>(ObjectHandler::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); } OH_FAIL("operToVector: error converting parameter '" << paramName << "' : " << e.what()); } }
inline void Observable::notifyObservers() { bool successful = true; for (iterator i=observers_.begin(); i!=observers_.end(); ++i) { try { (*i)->update(); } catch (...) { // quite a dilemma. If we don't catch the exception, // other observers will not receive the notification // and might be left in an incorrect state. If we do // catch it and continue the loop (as we do here) we // lose the exception. The least evil might be to try // and notify all observers, while raising an // exception if something bad happened. successful = false; } } OH_REQUIRE(successful, "could not notify one or more observers"); }
FunctionCall::FunctionCall(const std::string functionName) : functionName_(functionName), callerDimensions_(CallerDimensions::Uninitialized), error_(false) { OH_REQUIRE(!instance_, "Multiple attempts to initialize global FunctionCall object"); instance_ = this; Excel(xlfCaller, &xCaller_, 0); if (xCaller_->xltype == xltypeRef || xCaller_->xltype == xltypeSRef) { Excel(xlfReftext, &xReftext_, 1, &xCaller_); refStr_ = ConvertOper(xReftext_()); callerType_ = CallerType::Cell; } else if (xCaller_->xltype & xltypeErr) { callerType_ = CallerType::VBA; } else if (xCaller_->xltype == xltypeMulti) { callerType_ = CallerType::Menu; } else { callerType_ = CallerType::Unknown; } }
bool handleToObject( const boost::shared_ptr<ObjectHandler::Object> &in, boost::shared_ptr<ObjectTo> &out) { // FIXME gcc doesn't like this typedef //typedef RelinkableHandleImpl<ObjectFrom, LibraryFrom> HandleClass; //boost::shared_ptr<HandleClass> handle = // boost::dynamic_pointer_cast<HandleClass>(in); boost::shared_ptr<RelinkableHandleImpl<ObjectFrom, LibraryFrom> > handle = boost::dynamic_pointer_cast<RelinkableHandleImpl<ObjectFrom, LibraryFrom> >(in); if (!handle) return false; out = boost::dynamic_pointer_cast<ObjectTo>(handle->object()); OH_REQUIRE(out, "unable to convert reference from class '" << typeid(ObjectFrom).name()<< "' to class '" << typeid(ObjectTo).name() << "'"); return true; }
string RepositoryXL::retrieveError(const XLOPER *xRangeRef) { OH_REQUIRE(xRangeRef->xltype == xltypeRef || xRangeRef->xltype == xltypeSRef, "Input parameter is not a range reference."); Xloper xRangeText; Excel(xlfReftext, &xRangeText, 1, xRangeRef); string refStr = ConvertOper(xRangeText()); string refStrUpper = boost::algorithm::to_upper_copy(refStr); ErrorMessageMap::const_iterator i = errorMessageMap_.find(refStrUpper); if (i != errorMessageMap_.end()) return i->second->errorMessage(); RangeReference selectionReference(refStrUpper); for (i = errorMessageMap_.begin(); i != errorMessageMap_.end(); ++i) { if (i->second->contains(selectionReference)) return i->second->errorMessage(); } return ""; }
std::vector<std::vector<T> > operToMatrixImpl( const ConvertOper &xMatrix, const std::string ¶mName) { try { if (xMatrix.missing()) return std::vector<std::vector<T> >(); OH_REQUIRE(!xMatrix.error(), "input value has type=error"); const OPER *xMulti; Xloper xCoerce; // Freed automatically if (xMatrix->xltype == xltypeMulti) xMulti = xMatrix.get(); else { Excel(xlCoerce, &xCoerce, 2, xMatrix.get(), TempInt(xltypeMulti)); xMulti = &xCoerce; } std::vector<std::vector<T> > ret; ret.reserve(xMulti->val.array.rows); for (int i=0; i<xMulti->val.array.rows; ++i) { std::vector<T> row; row.reserve(xMulti->val.array.columns); for (int j=0; j<xMulti->val.array.columns; ++j) { row.push_back(convert2<T>(ConvertOper(xMulti->val.array.lparray[i * xMulti->val.array.columns + j]))); } ret.push_back(row); } return ret; } catch (const std::exception &e) { OH_FAIL("operToMatrixImpl: error converting parameter '" << paramName << "' to type '" << typeid(T).name() << "' : " << e.what()); } }
FunctionCall &FunctionCall::instance() { OH_REQUIRE(instance_, "Attempt to reference uninitialized FunctionCall object"); return *instance_; }
/* Parse the joint calendar ID. A JointCalendar ID is in a format such as JoinHolidays(UnitedStates::Settlement, UnitedKingdom::Exchange) - the initial string is either "JoinHolidays" or "JoinBusinessDays" - the parentheses contain a comma-delimited list of 2, 3 or 4 calendar IDs - a calendar ID can be in format "abcd" or "abcd::efgh" */ void Create<QuantLib::Calendar>::parseID() { // strip out whitespace (NB ~50% of elapsed time spent here) static boost::regex regex_whitespace("\\s"); std::string idStrip = boost::regex_replace(idUpper, regex_whitespace, ""); // parse the ID (the other ~50%). static boost::regex jointCalendarID( "((?:JOINHOLIDAYS)|(?:JOINBUSINESSDAYS))\\((.+?),(.+?)(?:,(.+?))?(?:,(.+))?\\)"); boost::smatch m; OH_REQUIRE(boost::regex_match(idStrip, m, jointCalendarID), "the string '" << idOriginal << "' is not a valid joint calendar identifier"); // Derive the inputs to the JointCalendar constructor. // Add the calendar IDs to a set where they will be uniquely sorted. std::set<std::string> calendarIdSet; // Given that the regex succeeded, we're guaranteed :-) to have // m[1] - "JOINHOLIDAYS"/"JOINBUSINESSDAYS" // m[2] - the ID of the first calendar // m[3] - the ID of the second calendar if (m[1] == "JOINHOLIDAYS") jointCalendarRule = QuantLib::JointCalendarRule(QuantLib::JoinHolidays); else // "JOINBUSINESSDAYS" jointCalendarRule = QuantLib::JointCalendarRule(QuantLib::JoinBusinessDays); calendarIdSet.insert(m[2]); calendarIdSet.insert(m[3]); // we may have a 3rd or a 3rd & 4th calendar if (m[5].matched) { calendarIdSet.insert(m[4]); calendarIdSet.insert(m[5]); } else if (m[4].matched) { calendarIdSet.insert(m[4]); } // if the list of calendars contained duplicates, // we may end up with just one value, which is invalid OH_REQUIRE(calendarIdSet.size() > 1, "the string '" << idOriginal << "' is not a valid joint calendar identifier"); /* 1) transfer the IDs from the set to a vector 2) in the same loop, format a unique key "idFull" for the object, this will be the same as the ID provided by the user e.g. JoinHolidays(UnitedStates::Settlement, UnitedKingdom::Exchange) -> uppercase, no whitespace, IDs sorted alphabetically e.g. JOINHOLIDAYS(UNITEDKINGDOM::EXCHANGE,UNITEDSTATES::SETTLEMENT) */ std::set<std::string>::const_iterator i = calendarIdSet.begin(); std::ostringstream s; s << m[1] << "(" << *i; calendarIDs.push_back(*i); i++; while (i != calendarIdSet.end()) { calendarIDs.push_back(*i); s << "," << *i; i++; } s << ")"; idFull = s.str(); }
// Retrieve the Caller pointer corresponding to a given InterpolatedYieldCurvePair const CallerBase *getCaller(InterpolatedYieldCurvePair tokenPair) const { CallerMap::const_iterator i = callerMap_.find(tokenPair); OH_REQUIRE(i!=callerMap_.end(), "Unable to retrieve caller for type " << tokenPair); return i->second; }
void validateReference(const XLOPER *xReference, const std::string &name) { OH_REQUIRE(xReference->xltype != xltypeErr && xReference->val.err != xlerrRef, "parameter '" << name << "' is not a valid range reference"); }
const boost::shared_ptr<ObjectClass> &object() const { OH_REQUIRE(object_, "Attempt to retrieve null object reference"); return object_; }