CMS 3D CMS Logo

ClassId.cc
Go to the documentation of this file.
1 #include "Alignment/Geners/interface/IOException.hh"
2 #include <cassert>
3 #include <cctype>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <cstring>
7 #include <sstream>
8 
9 #include "Alignment/Geners/interface/ClassId.hh"
10 #include "Alignment/Geners/interface/IOException.hh"
11 #include "Alignment/Geners/interface/binaryIO.hh"
12 
13 #define NLOCAL 1024
14 
15 namespace gs {
16  void ClassId::setVersion(const unsigned newVersion) {
17  if (version_ != newVersion) {
18  version_ = newVersion;
19 
20  // Need to update the id string
21  const std::size_t lastOpen = id_.find_last_of('(');
22  assert(lastOpen != std::string::npos);
23 
24  std::ostringstream os;
25  os << id_.substr(0, lastOpen) << '(' << version_ << ')';
26  if (isPtr_)
27  os << '*';
28  id_ = os.str();
29  }
30  }
31 
32  void ClassId::ensureSameId(const ClassId &id) const {
33  if (name_.empty())
34  throw gs::IOInvalidArgument("In gs::ClassId::ensureSameId: reference id is not valid");
35  if (id.name_.empty())
36  throw gs::IOInvalidArgument("In gs::ClassId::ensureSameId: argument id is not valid");
37  if (id_ != id.id_) {
38  std::ostringstream os;
39  os << "In gs::ClassId::ensureSameId: expected \"" << id_ << "\", got \"" << id.id_ << "\"";
40  throw gs::IOInvalidArgument(os.str());
41  }
42  }
43 
44  void ClassId::ensureSameName(const ClassId &id) const {
45  if (name_.empty())
46  throw gs::IOInvalidArgument("In gs::ClassId::ensureSameName: reference id is not valid");
47  if (id.name_.empty())
48  throw gs::IOInvalidArgument("In gs::ClassId::ensureSameName: argument id is not valid");
49  if (name_ != id.name_) {
50  std::ostringstream os;
51  os << "In gs::ClassId::ensureSameName: expected class name \"" << name_ << "\", got \"" << id.name_ << "\"";
52  throw gs::IOInvalidArgument(os.str());
53  }
54  }
55 
56  void ClassId::ensureSameVersion(const ClassId &id) const {
57  if (name_.empty())
58  throw gs::IOInvalidArgument("In gs::ClassId::ensureSameVersion: reference id is not valid");
59  if (id.name_.empty())
60  throw gs::IOInvalidArgument("In gs::ClassId::ensureSameVersion: argument id is not valid");
61  if (version_ != id.version_) {
62  std::ostringstream os;
63  os << "In gs::ClassId::ensureSameVersion: expected version " << version_ << " for class " << id.name_ << ", got "
64  << id.version_;
65  throw gs::IOInvalidArgument(os.str());
66  }
67  }
68 
69  void ClassId::ensureVersionInRange(const unsigned vmin, const unsigned vmax) const {
70  if (name_.empty())
71  throw gs::IOInvalidArgument("In gs::ClassId::ensureVersionInRange: id is not valid");
72  if (version_ < vmin || version_ > vmax) {
73  std::ostringstream os;
74  os << "In gs::ClassId::ensureVersionInRange: expected version"
75  << " number for class " << name_ << " to be in range [" << vmin << ", " << vmax << "], got " << version_;
76  throw gs::IOInvalidArgument(os.str());
77  }
78  }
79 
80  bool ClassId::validatePrefix(const char *prefix) {
81  // Prefix can not be an empty string
82  if (prefix == nullptr)
83  return false;
84  const unsigned len = strlen(prefix);
85  if (len == 0)
86  return false;
87 
88  // Characters '(' and ')' are special and can not be used
89  // as parts of class names unless they enclose a version
90  // number. Version number is an unsigned integer.
91  bool inVersion = false;
92  unsigned vstart = 0;
93  for (unsigned i = 0; i < len; ++i) {
94  if (prefix[i] == '(') {
95  // Can't have stacked parentheses.
96  // Can't have '(' as the very first character.
97  if (inVersion || i == 0)
98  return false;
99  inVersion = true;
100  vstart = i + 1;
101  } else if (prefix[i] == ')') {
102  // Can't have closing parentheses withoup opening ones
103  if (!inVersion)
104  return false;
105  inVersion = false;
106  if (vstart >= i)
107  return false;
108  char *endptr;
109  // Compiler can complain about unused result of "strtoul"
110  strtoul(prefix + vstart, &endptr, 10);
111  if (endptr != prefix + i)
112  return false;
113  }
114  }
115  // Can't have missing closing parentheses
116  if (inVersion)
117  return false;
118 
119  return true;
120  }
121 
122  void ClassId::initialize(const char *prefix, const unsigned version, const bool isPtr) {
123  std::ostringstream os;
124  if (!validatePrefix(prefix)) {
125  if (prefix)
126  os << "In gs::ClassId::initialize: bad class name prefix \"" << prefix
127  << "\". Check for problematic parentheses.";
128  else
129  os << "In gs::ClassId::initialize: NULL class name prefix.";
130  throw gs::IOInvalidArgument(os.str());
131  }
132  os << prefix << '(' << version << ')';
133  if (isPtr)
134  os << '*';
135  id_ = os.str();
136  version_ = version;
137  isPtr_ = isPtr;
138  makeName();
139  }
140 
141  // Remove all version numbers from the class id
142  bool ClassId::makeName() {
143  char localbuf[NLOCAL];
144  char *buf = localbuf;
145  const unsigned idLen = id_.size();
146  if (idLen + 1U > NLOCAL)
147  buf = new char[idLen + 1U];
148  const char *from = id_.data();
149  bool inVersion = false;
150  unsigned ito = 0;
151  for (unsigned ifrom = 0; ifrom < idLen; ++ifrom) {
152  if (from[ifrom] == '(') {
153  if (inVersion) {
154  if (buf != localbuf)
155  delete[] buf;
156  return false;
157  }
158  inVersion = true;
159  } else if (from[ifrom] == ')') {
160  if (!inVersion) {
161  if (buf != localbuf)
162  delete[] buf;
163  return false;
164  }
165  inVersion = false;
166  } else if (!inVersion)
167  buf[ito++] = from[ifrom];
168  }
169  if (inVersion) {
170  if (buf != localbuf)
171  delete[] buf;
172  return false;
173  }
174  buf[ito] = '\0';
175  name_ = buf;
176  if (buf != localbuf)
177  delete[] buf;
178  return true;
179  }
180 
181  // Parse the version number and pointer switch
182  bool ClassId::makeVersion() {
183  bool correct = false;
184  const unsigned ns = id_.size();
185  const char *const buf = id_.data();
186  const char *sep = buf + (ns - 1U);
187  if (*sep == '*') {
188  isPtr_ = true;
189  --sep;
190  } else
191  isPtr_ = false;
192  if (*sep == ')') {
193  const char *closingBrace = sep;
194  for (; sep != buf; --sep)
195  if (*sep == '(')
196  break;
197  if (sep != buf) {
198  char *endptr;
199  version_ = strtoul(sep + 1, &endptr, 10);
200  if (endptr > sep + 1 && endptr == closingBrace)
201  correct = true;
202  }
203  }
204  return correct;
205  }
206 
207  ClassId::ClassId(const std::string &id) : id_(id) {
208  if (!(!id_.empty() && makeName() && makeVersion())) {
209  std::ostringstream os;
210  os << "In gs::ClassId::ClassId(const std::string&): "
211  << "invalid input id string \"" << id_ << "\"";
212  throw gs::IOInvalidArgument(os.str());
213  }
214  }
215 
216  ClassId::ClassId(std::istream &in, int) {
217  read_pod(in, &id_);
218  if (in.fail())
219  throw IOReadFailure(
220  "In gs::ClassId::ClassId(std::istream&, int): "
221  "input stream failure");
222 
223  if (!(!id_.empty() && makeName() && makeVersion())) {
224  std::ostringstream os;
225  os << "In gs::ClassId::ClassId(std::istream&, int): "
226  << "read invalid id string \"" << id_ << "\"";
227  throw IOInvalidData(os.str());
228  }
229  }
230 
231  bool ClassId::write(std::ostream &os) const {
232  write_pod(os, id_);
233  return !os.fail();
234  }
235 
236  ClassId::ClassId() : name_(""), id_("(0)"), version_(0U), isPtr_(false) {}
237 
238  ClassId ClassId::invalidId() {
239  ClassId dummy;
240  return dummy;
241  }
242 
243  bool ClassId::isTemplate() const {
244  const std::size_t leftBrak = id_.find('<');
245  const std::size_t rightBrak = id_.rfind('>');
246  return leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak;
247  }
248 
249  void ClassId::templateParameters(std::vector<std::vector<ClassId>> *params) const {
250  assert(params);
251  params->clear();
252  const std::size_t leftBrak = id_.find('<');
253  const std::size_t rightBrak = id_.rfind('>');
254  if (leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak) {
255  // Count commas and angle brackets
256  unsigned ncommas = 0;
257  int nbrackets = 0;
258  for (std::size_t pos = leftBrak + 1; pos < rightBrak; ++pos) {
259  const char c = id_[pos];
260  if (c == '<')
261  ++nbrackets;
262  else if (c == '>')
263  --nbrackets;
264  else if (c == ',' && nbrackets == 0)
265  ++ncommas;
266  }
267 
268  // Must be a well-formed name
269  if (nbrackets) {
270  std::ostringstream os;
271  os << "In gs::ClassId::templateParameters: "
272  << "unbalanced angle brackets in the "
273  << "template id \"" << id_ << "\"";
274  throw gs::IOInvalidArgument(os.str());
275  }
276 
277  // Reserve a proper size vector
278  params->resize(ncommas + 1);
279  for (unsigned i = 0; i <= ncommas; ++i)
280  (*params)[i].reserve(1);
281 
282  // Cycle over commas again and fill the ids
283  ncommas = 0;
284  nbrackets = 0;
285  std::size_t begin = leftBrak + 1;
286  for (std::size_t pos = begin; pos < rightBrak; ++pos) {
287  const char c = id_[pos];
288  if (c == '<')
289  ++nbrackets;
290  else if (c == '>')
291  --nbrackets;
292  else if (c == ',' && nbrackets == 0) {
293  while (isspace(id_[begin]))
294  ++begin;
295  std::size_t end = pos - 1;
296  while (isspace(id_[end]))
297  --end;
298  ++end;
299  (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
300  begin = pos + 1;
301  ++ncommas;
302  }
303  }
304  while (isspace(id_[begin]))
305  ++begin;
306  std::size_t end = rightBrak - 1;
307  while (isspace(id_[end]))
308  --end;
309  ++end;
310  (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
311  }
312  }
313 } // namespace gs
static AlgebraicMatrix initialize()
assert(be >=bs)
#define NLOCAL
Definition: ClassId.cc:13
Definition: AbsArchive.cc:46