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
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
0082 if (prefix == nullptr)
0083 return false;
0084 const unsigned len = strlen(prefix);
0085 if (len == 0)
0086 return false;
0087
0088
0089
0090
0091 bool inVersion = false;
0092 unsigned vstart = 0;
0093 for (unsigned i = 0; i < len; ++i) {
0094 if (prefix[i] == '(') {
0095
0096
0097 if (inVersion || i == 0)
0098 return false;
0099 inVersion = true;
0100 vstart = i + 1;
0101 } else if (prefix[i] == ')') {
0102
0103 if (!inVersion)
0104 return false;
0105 inVersion = false;
0106 if (vstart >= i)
0107 return false;
0108 char *endptr;
0109
0110 unsigned long dummy = strtoul(prefix + vstart, &endptr, 10);
0111 ++dummy;
0112 if (endptr != prefix + i)
0113 return false;
0114 }
0115 }
0116
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
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
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
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
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
0279 params->resize(ncommas + 1);
0280 for (unsigned i = 0; i <= ncommas; ++i)
0281 (*params)[i].reserve(1);
0282
0283
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 }