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
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 strtoul(prefix + vstart, &endptr, 10);
0111 if (endptr != prefix + i)
0112 return false;
0113 }
0114 }
0115
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
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
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
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
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
0278 params->resize(ncommas + 1);
0279 for (unsigned i = 0; i <= ncommas; ++i)
0280 (*params)[i].reserve(1);
0281
0282
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 }