//C++ #ifndef HANDLERUTILS_H #define HANDLERUTILS_H #include <xsTypes.h> #include <XSstreams.h> #include <XSFit/Fit/Step.h> #include <XSUser/UserInterface/xstcl.h> #include <XSUtil/Error/Error.h> #include <XSUtil/Parse/XSRegEx.h> #include <XSUtil/Parse/XSparse.h> #include <functional> #include <sstream> class Model; class Parameter; class Component; class TclRegEx; class Response; class ResponseParam; // These clases and utilities depend on objects defined in libXSModel, // which is why they are not included in the usual XSutility and // XSparse files. They also tend to depend on tcl, which is why they are // here and not in XSModel. // Traits classes template<typename T> class CmdRetrievalTraits; template<> class CmdRetrievalTraits<Parameter> { public: static const std::string reqString; static const std::string objName; }; template<> class CmdRetrievalTraits<Component> { public: static const std::string reqString; static const std::string objName; }; template<> class CmdRetrievalTraits<Response> { public: static const std::string reqString; static const std::string objName; }; template<> class CmdRetrievalTraits<ResponseParam> { public: static const std::string reqString; static const std::string objName; }; // Policy classes template<typename T> class LookupPolicy; template<> class LookupPolicy<Parameter> { public: static Parameter* get(const string& name, size_t num); }; template<> class LookupPolicy<Model> { public: static Model* get(const string& name, size_t num); }; template<> class LookupPolicy<Component> { public: static Component* get(const string& name, size_t num); }; template<> class LookupPolicy<Response> { public: static Response* get(const size_t defSource, const size_t defSpec, size_t& sourceNum, size_t& specNum); }; template<> class LookupPolicy<ResponseParam> { public: // Each of these does the same thing. The second 2 interfaces // are to allow interchangability with Response and Parameter // objects respectively. static ResponseParam* get(size_t sourceNum, size_t parNum); static ResponseParam* get(const size_t defSource, const size_t defPar, size_t& sourceNum, size_t& parNum); static ResponseParam* get(const string& name, size_t num); }; // Originally designed for freeze/thaw/untie template<typename T> class RangeFindPolicy; template<> class RangeFindPolicy<Parameter> { public: static IntegerArray getIndices(const string& modName, const StringArray& rangeStrs, RangePair& prevRange); }; template<> class RangeFindPolicy<ResponseParam> { public: static IntegerArray getIndices(const string& sourceName, const StringArray& rangeStrs, RangePair& prevRange); }; namespace HandlerUtils { typedef XSRegEx<TclRegEx> RegEx; // Template functions utilizing the FIXED traits style described by // Vandevoorde and Josuttis, not Alexandrescu's more complicated // parameterized style. template<typename T> T* lookupStringIntObj(const string& name, size_t idx); template <typename T> bool verifyStringInt(const StringArray& rawArgs, size_t pos, string& name, size_t& idx); template <typename T> T* getFromStringInt(const StringArray& rawArgs); // The arg string should contain the int pair or be empty. // "first" and "second" will be set to the indices of the returned T*, // as determined from the arg string. If arg string is empty, it looks // for T* given by input "first" and "second". If only 1 int is found in arg // (and no colon) it will be applied to "second", and "first" will retain // its input value. // Doing it this way since "first" is expected to represent the // optional sourceNum parameter in most scenarios. // // NOTE: Internal T* lookup functions have the right to change "first" // or "second" through reprompting, and they may throw. // // If unable to find an object at the requested position, returns 0. // "first" and "second" will be set to the values of the attempted position. // // Throws if invalid syntax or negative integers, in which case // "first" and "second" will be unchanged from their input values. template <typename T> T* getFromIntPair(const string& arg, int& first, int& second); // Generic function to do the bulk of the work common to the // freeze/thaw/untie commands. T must be a type for which // LookupPolicy and RangeFindPolicy classes are defined. // U is a strategy class defined by and specific to the individual // command handler. // // groupName is the left-of-colon group specifier, ie. modName or sourceNum, // and may be empty. rangeStrs are all the range string specifiers for // the group. prevRange will be filled with the last entered range. // Returns true if ANY parameter has had its f/t/u state modified. template <typename T, typename U> bool freezeThawUntie(const string& groupName, const StringArray& rangeStrs, RangePair& prevRange); // Non-templated utilities // Does a 1-to-1 copy from each Tcl object in objv (including the 1st) // to a string in cppArgs. cppArgs will be resized to objc. void tclArgsToCpp(const int objc, Tcl_Obj* CONST objv[], StringArray& cppArgs); bool getSpecNumParameter(const StringArray& rawArgs, const string& opt, size_t argNum, size_t& specNum); const Model* getModFromArg(const StringArray& rawArgs); const Model* getModFromName(const string& name); bool subExpMatched (const Tcl_RegExpInfo& regExpInfo, const string& search, int index, std::string& group); bool subExpMatched (const Tcl_RegExpInfo& regExpInfo, const string& search, const IntegerArray& indices, std::map<int, std::string >& group); bool compileAndMatch(const string& pattern, const string& search, const string& whole, Tcl_RegExpInfo& expInfo); bool fillArrays(const Tcl_RegExpInfo& expInfo, const string& arg, std::vector<Real> first, std::vector<Real> second, std::vector<Real>& _default); bool fillArrays(const Tcl_RegExpInfo& expInfo, const std::string& arg, std::vector<Real>& first, std::vector<Real>& second, std::vector<Real>& _default, const IntegerArray& subs); void IgnoreNoticeParse(const StringArray& args, std::vector<Real>& prevRanges, bool& isReal, bool& isRespChanged, bool& isChanged, bool value); bool fileExists(const string& fileName, std::ofstream& out); bool analyzeInfix(const string& infix, string& postfix); void commonStepParsing(const StringArray& rawArgs, Grid::ParameterSpec*& prevSettings, Grid::SpecContainer& newStepSettings, bool& isBest, bool needModParam = true); struct CompareSource : public std::binary_function<Model*, Model*, bool> { public: bool operator() (Model* right, Model* left); }; class FreezeThawRange { public: static const RangePair& getRange() {return s_range;} static void setRange(const RangePair& newRange) {s_range = newRange;} static const string& getGroupName() {return s_groupName;} static void setGroupName(const string& groupName) {s_groupName = groupName;} private: static RangePair s_range; static string s_groupName; }; } template <typename T> T* HandlerUtils::lookupStringIntObj(const string& name, size_t idx) { T* pT = 0; pT = LookupPolicy<T>::get(name, idx); if (!pT) { std::ostringstream concat; if (name.length()) { concat << name << ":" << idx; } else { concat << "[(unnamed):]" << idx; } string errMsg = "Cannot locate "; errMsg += CmdRetrievalTraits<T>::objName + " specified by: " + concat.str(); tcerr << errMsg << std::endl; } return pT; } template <typename T> bool HandlerUtils::verifyStringInt(const StringArray& rawArgs, size_t pos, string& name, size_t& idx) { bool status = true; string errMsg = "Must specify "; errMsg += CmdRetrievalTraits<T>::reqString; if (rawArgs.size() < pos) { tcerr << errMsg << std::endl; status = false; } else { string arg(rawArgs[pos-1]); name = string(""); idx = string::npos; XSparse::stringIntPair(arg, name, idx); if (idx == string::npos) { tcerr << errMsg << std::endl; status = false; } } return status; } template <typename T> T* HandlerUtils::getFromStringInt(const StringArray& rawArgs) { T* pT = 0; string name; size_t idx=string::npos; if (verifyStringInt<T>(rawArgs, 3, name, idx)) { pT = lookupStringIntObj<T>(name, idx); } return pT; } template <typename T> T* HandlerUtils::getFromIntPair(const string& arg, int& first, int& second) { T* pT = 0; int i1=0, i2=0; bool validSyntax = false; if (!arg.length()) { i1 = first; i2 = second; validSyntax = true; } else if (XSparse::integerPair(arg, i1, i2)) { if (i2 == -1) { // Only 1 int and no colon. Apply this to second for reasons // given in the function declaration above. i2 = i1; i1 = first; } validSyntax = true; } else { std::ostringstream errMsg; errMsg << "Invalid syntax: " << arg << ": should be of form " << CmdRetrievalTraits<T>::reqString << '\n'; throw YellowAlert(errMsg.str()); } if (validSyntax) { if (i1 < 0 || i2 < 0) { std::ostringstream errMsg; errMsg << "Negative indices are not allowed when selecting a " << CmdRetrievalTraits<T>::objName << " with\n" << CmdRetrievalTraits<T>::reqString << '\n'; throw YellowAlert(errMsg.str()); } else { size_t tmp1 = static_cast<size_t>(i1); size_t tmp2 = static_cast<size_t>(i2); // Assume that for some T this may change input args // due to reprompting. pT = LookupPolicy<T>::get(static_cast<size_t>(first), static_cast<size_t>(second),tmp1, tmp2); first = static_cast<int>(tmp1); second = static_cast<int>(tmp2); } } return pT; } template <typename T, typename U> bool freezeThawUntie(const string& groupName, const StringArray& rangeStrs, RangePair& prevRange) { bool isChanged = false; IntegerArray parIndices(RangeFindPolicy<T>::getIndices(groupName, rangeStrs, prevRange)); const size_t nPars = parIndices.size(); for (size_t i=0; i<nPars; ++i) { Parameter* par = LookupPolicy<T>::get(groupName, static_cast<size_t>(parIndices[i])); if (par) { string msg; if (!U::perform(par, msg)) { tcout << " "<< CmdRetrievalTraits<T>::objName << " "; if (groupName.length()) tcout << groupName <<":"; tcout << parIndices[i] << msg << std::endl; } else isChanged = true; } else { // Don't think it can even get here, as RangeFindPolicy // would most likely have thrown. Just to be sure... std::ostringstream oss; oss << "No such " << CmdRetrievalTraits<T>::objName << ": "; if (groupName.length()) oss << groupName <<":"; oss << parIndices[i] <<"\n"; throw YellowAlert(oss.str()); } } return isChanged; } #endif