Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-02-14 12:44:55

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         unsigned long dummy = strtoul(prefix + vstart, &endptr, 10);
0111         ++dummy;
0112         if (endptr != prefix + i)
0113           return false;
0114       }
0115     }
0116     // Can't have missing closing parentheses
0117     if (inVersion)
0118       return false;
0119 
0120     return true;
0121   }
0122 
0123   void ClassId::initialize(const char *prefix, const unsigned version, const bool isPtr) {
0124     std::ostringstream os;
0125     if (!validatePrefix(prefix)) {
0126       if (prefix)
0127         os << "In gs::ClassId::initialize: bad class name prefix \"" << prefix
0128            << "\". Check for problematic parentheses.";
0129       else
0130         os << "In gs::ClassId::initialize: NULL class name prefix.";
0131       throw gs::IOInvalidArgument(os.str());
0132     }
0133     os << prefix << '(' << version << ')';
0134     if (isPtr)
0135       os << '*';
0136     id_ = os.str();
0137     version_ = version;
0138     isPtr_ = isPtr;
0139     makeName();
0140   }
0141 
0142   // Remove all version numbers from the class id
0143   bool ClassId::makeName() {
0144     char localbuf[NLOCAL];
0145     char *buf = localbuf;
0146     const unsigned idLen = id_.size();
0147     if (idLen + 1U > NLOCAL)
0148       buf = new char[idLen + 1U];
0149     const char *from = id_.data();
0150     bool inVersion = false;
0151     unsigned ito = 0;
0152     for (unsigned ifrom = 0; ifrom < idLen; ++ifrom) {
0153       if (from[ifrom] == '(') {
0154         if (inVersion) {
0155           if (buf != localbuf)
0156             delete[] buf;
0157           return false;
0158         }
0159         inVersion = true;
0160       } else if (from[ifrom] == ')') {
0161         if (!inVersion) {
0162           if (buf != localbuf)
0163             delete[] buf;
0164           return false;
0165         }
0166         inVersion = false;
0167       } else if (!inVersion)
0168         buf[ito++] = from[ifrom];
0169     }
0170     if (inVersion) {
0171       if (buf != localbuf)
0172         delete[] buf;
0173       return false;
0174     }
0175     buf[ito] = '\0';
0176     name_ = buf;
0177     if (buf != localbuf)
0178       delete[] buf;
0179     return true;
0180   }
0181 
0182   // Parse the version number and pointer switch
0183   bool ClassId::makeVersion() {
0184     bool correct = false;
0185     const unsigned ns = id_.size();
0186     const char *const buf = id_.data();
0187     const char *sep = buf + (ns - 1U);
0188     if (*sep == '*') {
0189       isPtr_ = true;
0190       --sep;
0191     } else
0192       isPtr_ = false;
0193     if (*sep == ')') {
0194       const char *closingBrace = sep;
0195       for (; sep != buf; --sep)
0196         if (*sep == '(')
0197           break;
0198       if (sep != buf) {
0199         char *endptr;
0200         version_ = strtoul(sep + 1, &endptr, 10);
0201         if (endptr > sep + 1 && endptr == closingBrace)
0202           correct = true;
0203       }
0204     }
0205     return correct;
0206   }
0207 
0208   ClassId::ClassId(const std::string &id) : id_(id) {
0209     if (!(!id_.empty() && makeName() && makeVersion())) {
0210       std::ostringstream os;
0211       os << "In gs::ClassId::ClassId(const std::string&): "
0212          << "invalid input id string \"" << id_ << "\"";
0213       throw gs::IOInvalidArgument(os.str());
0214     }
0215   }
0216 
0217   ClassId::ClassId(std::istream &in, int) {
0218     read_pod(in, &id_);
0219     if (in.fail())
0220       throw IOReadFailure(
0221           "In gs::ClassId::ClassId(std::istream&, int): "
0222           "input stream failure");
0223 
0224     if (!(!id_.empty() && makeName() && makeVersion())) {
0225       std::ostringstream os;
0226       os << "In gs::ClassId::ClassId(std::istream&, int): "
0227          << "read invalid id string \"" << id_ << "\"";
0228       throw IOInvalidData(os.str());
0229     }
0230   }
0231 
0232   bool ClassId::write(std::ostream &os) const {
0233     write_pod(os, id_);
0234     return !os.fail();
0235   }
0236 
0237   ClassId::ClassId() : name_(""), id_("(0)"), version_(0U), isPtr_(false) {}
0238 
0239   ClassId ClassId::invalidId() {
0240     ClassId dummy;
0241     return dummy;
0242   }
0243 
0244   bool ClassId::isTemplate() const {
0245     const std::size_t leftBrak = id_.find('<');
0246     const std::size_t rightBrak = id_.rfind('>');
0247     return leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak;
0248   }
0249 
0250   void ClassId::templateParameters(std::vector<std::vector<ClassId>> *params) const {
0251     assert(params);
0252     params->clear();
0253     const std::size_t leftBrak = id_.find('<');
0254     const std::size_t rightBrak = id_.rfind('>');
0255     if (leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak) {
0256       // Count commas and angle brackets
0257       unsigned ncommas = 0;
0258       int nbrackets = 0;
0259       for (std::size_t pos = leftBrak + 1; pos < rightBrak; ++pos) {
0260         const char c = id_[pos];
0261         if (c == '<')
0262           ++nbrackets;
0263         else if (c == '>')
0264           --nbrackets;
0265         else if (c == ',' && nbrackets == 0)
0266           ++ncommas;
0267       }
0268 
0269       // Must be a well-formed name
0270       if (nbrackets) {
0271         std::ostringstream os;
0272         os << "In gs::ClassId::templateParameters: "
0273            << "unbalanced angle brackets in the "
0274            << "template id \"" << id_ << "\"";
0275         throw gs::IOInvalidArgument(os.str());
0276       }
0277 
0278       // Reserve a proper size vector
0279       params->resize(ncommas + 1);
0280       for (unsigned i = 0; i <= ncommas; ++i)
0281         (*params)[i].reserve(1);
0282 
0283       // Cycle over commas again and fill the ids
0284       ncommas = 0;
0285       nbrackets = 0;
0286       std::size_t begin = leftBrak + 1;
0287       for (std::size_t pos = begin; pos < rightBrak; ++pos) {
0288         const char c = id_[pos];
0289         if (c == '<')
0290           ++nbrackets;
0291         else if (c == '>')
0292           --nbrackets;
0293         else if (c == ',' && nbrackets == 0) {
0294           while (isspace(id_[begin]))
0295             ++begin;
0296           std::size_t end = pos - 1;
0297           while (isspace(id_[end]))
0298             --end;
0299           ++end;
0300           (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
0301           begin = pos + 1;
0302           ++ncommas;
0303         }
0304       }
0305       while (isspace(id_[begin]))
0306         ++begin;
0307       std::size_t end = rightBrak - 1;
0308       while (isspace(id_[end]))
0309         --end;
0310       ++end;
0311       (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
0312     }
0313   }
0314 }  // namespace gs