Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 11:56:21

0001 #include "Alignment/Geners/interface/IOException.hh"
0002 #include <cassert>
0003 #include <cctype>
0004 #include <cstdio>
0005 #include <cstdlib>
0006 #include <cstring>
0007 #include <sstream>
0008 
0009 #include "Alignment/Geners/interface/ClassId.hh"
0010 #include "Alignment/Geners/interface/IOException.hh"
0011 #include "Alignment/Geners/interface/binaryIO.hh"
0012 
0013 #define NLOCAL 1024
0014 
0015 namespace gs {
0016   void ClassId::setVersion(const unsigned newVersion) {
0017     if (version_ != newVersion) {
0018       version_ = newVersion;
0019 
0020       // Need to update the id string
0021       const std::size_t lastOpen = id_.find_last_of('(');
0022       assert(lastOpen != std::string::npos);
0023 
0024       std::ostringstream os;
0025       os << id_.substr(0, lastOpen) << '(' << version_ << ')';
0026       if (isPtr_)
0027         os << '*';
0028       id_ = os.str();
0029     }
0030   }
0031 
0032   void ClassId::ensureSameId(const ClassId &id) const {
0033     if (name_.empty())
0034       throw gs::IOInvalidArgument("In gs::ClassId::ensureSameId: reference id is not valid");
0035     if (id.name_.empty())
0036       throw gs::IOInvalidArgument("In gs::ClassId::ensureSameId: argument id is not valid");
0037     if (id_ != id.id_) {
0038       std::ostringstream os;
0039       os << "In gs::ClassId::ensureSameId: expected \"" << id_ << "\", got \"" << id.id_ << "\"";
0040       throw gs::IOInvalidArgument(os.str());
0041     }
0042   }
0043 
0044   void ClassId::ensureSameName(const ClassId &id) const {
0045     if (name_.empty())
0046       throw gs::IOInvalidArgument("In gs::ClassId::ensureSameName: reference id is not valid");
0047     if (id.name_.empty())
0048       throw gs::IOInvalidArgument("In gs::ClassId::ensureSameName: argument id is not valid");
0049     if (name_ != id.name_) {
0050       std::ostringstream os;
0051       os << "In gs::ClassId::ensureSameName: expected class name \"" << name_ << "\", got \"" << id.name_ << "\"";
0052       throw gs::IOInvalidArgument(os.str());
0053     }
0054   }
0055 
0056   void ClassId::ensureSameVersion(const ClassId &id) const {
0057     if (name_.empty())
0058       throw gs::IOInvalidArgument("In gs::ClassId::ensureSameVersion: reference id is not valid");
0059     if (id.name_.empty())
0060       throw gs::IOInvalidArgument("In gs::ClassId::ensureSameVersion: argument id is not valid");
0061     if (version_ != id.version_) {
0062       std::ostringstream os;
0063       os << "In gs::ClassId::ensureSameVersion: expected version " << version_ << " for class " << id.name_ << ", got "
0064          << id.version_;
0065       throw gs::IOInvalidArgument(os.str());
0066     }
0067   }
0068 
0069   void ClassId::ensureVersionInRange(const unsigned vmin, const unsigned vmax) const {
0070     if (name_.empty())
0071       throw gs::IOInvalidArgument("In gs::ClassId::ensureVersionInRange: id is not valid");
0072     if (version_ < vmin || version_ > vmax) {
0073       std::ostringstream os;
0074       os << "In gs::ClassId::ensureVersionInRange: expected version"
0075          << " number for class " << name_ << " to be in range [" << vmin << ", " << vmax << "], got " << version_;
0076       throw gs::IOInvalidArgument(os.str());
0077     }
0078   }
0079 
0080   bool ClassId::validatePrefix(const char *prefix) {
0081     // Prefix can not be an empty string
0082     if (prefix == nullptr)
0083       return false;
0084     const unsigned len = strlen(prefix);
0085     if (len == 0)
0086       return false;
0087 
0088     // Characters '(' and ')' are special and can not be used
0089     // as parts of class names unless they enclose a version
0090     // number. Version number is an unsigned integer.
0091     bool inVersion = false;
0092     unsigned vstart = 0;
0093     for (unsigned i = 0; i < len; ++i) {
0094       if (prefix[i] == '(') {
0095         // Can't have stacked parentheses.
0096         // Can't have '(' as the very first character.
0097         if (inVersion || i == 0)
0098           return false;
0099         inVersion = true;
0100         vstart = i + 1;
0101       } else if (prefix[i] == ')') {
0102         // Can't have closing parentheses withoup opening ones
0103         if (!inVersion)
0104           return false;
0105         inVersion = false;
0106         if (vstart >= i)
0107           return false;
0108         char *endptr;
0109         // Compiler can complain about unused result of "strtoul"
0110         strtoul(prefix + vstart, &endptr, 10);
0111         if (endptr != prefix + i)
0112           return false;
0113       }
0114     }
0115     // Can't have missing closing parentheses
0116     if (inVersion)
0117       return false;
0118 
0119     return true;
0120   }
0121 
0122   void ClassId::initialize(const char *prefix, const unsigned version, const bool isPtr) {
0123     std::ostringstream os;
0124     if (!validatePrefix(prefix)) {
0125       if (prefix)
0126         os << "In gs::ClassId::initialize: bad class name prefix \"" << prefix
0127            << "\". Check for problematic parentheses.";
0128       else
0129         os << "In gs::ClassId::initialize: NULL class name prefix.";
0130       throw gs::IOInvalidArgument(os.str());
0131     }
0132     os << prefix << '(' << version << ')';
0133     if (isPtr)
0134       os << '*';
0135     id_ = os.str();
0136     version_ = version;
0137     isPtr_ = isPtr;
0138     makeName();
0139   }
0140 
0141   // Remove all version numbers from the class id
0142   bool ClassId::makeName() {
0143     char localbuf[NLOCAL];
0144     char *buf = localbuf;
0145     const unsigned idLen = id_.size();
0146     if (idLen + 1U > NLOCAL)
0147       buf = new char[idLen + 1U];
0148     const char *from = id_.data();
0149     bool inVersion = false;
0150     unsigned ito = 0;
0151     for (unsigned ifrom = 0; ifrom < idLen; ++ifrom) {
0152       if (from[ifrom] == '(') {
0153         if (inVersion) {
0154           if (buf != localbuf)
0155             delete[] buf;
0156           return false;
0157         }
0158         inVersion = true;
0159       } else if (from[ifrom] == ')') {
0160         if (!inVersion) {
0161           if (buf != localbuf)
0162             delete[] buf;
0163           return false;
0164         }
0165         inVersion = false;
0166       } else if (!inVersion)
0167         buf[ito++] = from[ifrom];
0168     }
0169     if (inVersion) {
0170       if (buf != localbuf)
0171         delete[] buf;
0172       return false;
0173     }
0174     buf[ito] = '\0';
0175     name_ = buf;
0176     if (buf != localbuf)
0177       delete[] buf;
0178     return true;
0179   }
0180 
0181   // Parse the version number and pointer switch
0182   bool ClassId::makeVersion() {
0183     bool correct = false;
0184     const unsigned ns = id_.size();
0185     const char *const buf = id_.data();
0186     const char *sep = buf + (ns - 1U);
0187     if (*sep == '*') {
0188       isPtr_ = true;
0189       --sep;
0190     } else
0191       isPtr_ = false;
0192     if (*sep == ')') {
0193       const char *closingBrace = sep;
0194       for (; sep != buf; --sep)
0195         if (*sep == '(')
0196           break;
0197       if (sep != buf) {
0198         char *endptr;
0199         version_ = strtoul(sep + 1, &endptr, 10);
0200         if (endptr > sep + 1 && endptr == closingBrace)
0201           correct = true;
0202       }
0203     }
0204     return correct;
0205   }
0206 
0207   ClassId::ClassId(const std::string &id) : id_(id) {
0208     if (!(!id_.empty() && makeName() && makeVersion())) {
0209       std::ostringstream os;
0210       os << "In gs::ClassId::ClassId(const std::string&): "
0211          << "invalid input id string \"" << id_ << "\"";
0212       throw gs::IOInvalidArgument(os.str());
0213     }
0214   }
0215 
0216   ClassId::ClassId(std::istream &in, int) {
0217     read_pod(in, &id_);
0218     if (in.fail())
0219       throw IOReadFailure(
0220           "In gs::ClassId::ClassId(std::istream&, int): "
0221           "input stream failure");
0222 
0223     if (!(!id_.empty() && makeName() && makeVersion())) {
0224       std::ostringstream os;
0225       os << "In gs::ClassId::ClassId(std::istream&, int): "
0226          << "read invalid id string \"" << id_ << "\"";
0227       throw IOInvalidData(os.str());
0228     }
0229   }
0230 
0231   bool ClassId::write(std::ostream &os) const {
0232     write_pod(os, id_);
0233     return !os.fail();
0234   }
0235 
0236   ClassId::ClassId() : name_(""), id_("(0)"), version_(0U), isPtr_(false) {}
0237 
0238   ClassId ClassId::invalidId() {
0239     ClassId dummy;
0240     return dummy;
0241   }
0242 
0243   bool ClassId::isTemplate() const {
0244     const std::size_t leftBrak = id_.find('<');
0245     const std::size_t rightBrak = id_.rfind('>');
0246     return leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak;
0247   }
0248 
0249   void ClassId::templateParameters(std::vector<std::vector<ClassId>> *params) const {
0250     assert(params);
0251     params->clear();
0252     const std::size_t leftBrak = id_.find('<');
0253     const std::size_t rightBrak = id_.rfind('>');
0254     if (leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak) {
0255       // Count commas and angle brackets
0256       unsigned ncommas = 0;
0257       int nbrackets = 0;
0258       for (std::size_t pos = leftBrak + 1; pos < rightBrak; ++pos) {
0259         const char c = id_[pos];
0260         if (c == '<')
0261           ++nbrackets;
0262         else if (c == '>')
0263           --nbrackets;
0264         else if (c == ',' && nbrackets == 0)
0265           ++ncommas;
0266       }
0267 
0268       // Must be a well-formed name
0269       if (nbrackets) {
0270         std::ostringstream os;
0271         os << "In gs::ClassId::templateParameters: "
0272            << "unbalanced angle brackets in the "
0273            << "template id \"" << id_ << "\"";
0274         throw gs::IOInvalidArgument(os.str());
0275       }
0276 
0277       // Reserve a proper size vector
0278       params->resize(ncommas + 1);
0279       for (unsigned i = 0; i <= ncommas; ++i)
0280         (*params)[i].reserve(1);
0281 
0282       // Cycle over commas again and fill the ids
0283       ncommas = 0;
0284       nbrackets = 0;
0285       std::size_t begin = leftBrak + 1;
0286       for (std::size_t pos = begin; pos < rightBrak; ++pos) {
0287         const char c = id_[pos];
0288         if (c == '<')
0289           ++nbrackets;
0290         else if (c == '>')
0291           --nbrackets;
0292         else if (c == ',' && nbrackets == 0) {
0293           while (isspace(id_[begin]))
0294             ++begin;
0295           std::size_t end = pos - 1;
0296           while (isspace(id_[end]))
0297             --end;
0298           ++end;
0299           (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
0300           begin = pos + 1;
0301           ++ncommas;
0302         }
0303       }
0304       while (isspace(id_[begin]))
0305         ++begin;
0306       std::size_t end = rightBrak - 1;
0307       while (isspace(id_[end]))
0308         --end;
0309       ++end;
0310       (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
0311     }
0312   }
0313 }  // namespace gs