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  unsigned long dummy = strtoul(prefix + vstart, &endptr, 10);
111  ++dummy;
112  if (endptr != prefix + i)
113  return false;
114  }
115  }
116  // Can't have missing closing parentheses
117  if (inVersion)
118  return false;
119 
120  return true;
121  }
122 
123  void ClassId::initialize(const char *prefix, const unsigned version, const bool isPtr) {
124  std::ostringstream os;
125  if (!validatePrefix(prefix)) {
126  if (prefix)
127  os << "In gs::ClassId::initialize: bad class name prefix \"" << prefix
128  << "\". Check for problematic parentheses.";
129  else
130  os << "In gs::ClassId::initialize: NULL class name prefix.";
131  throw gs::IOInvalidArgument(os.str());
132  }
133  os << prefix << '(' << version << ')';
134  if (isPtr)
135  os << '*';
136  id_ = os.str();
137  version_ = version;
138  isPtr_ = isPtr;
139  makeName();
140  }
141 
142  // Remove all version numbers from the class id
143  bool ClassId::makeName() {
144  char localbuf[NLOCAL];
145  char *buf = localbuf;
146  const unsigned idLen = id_.size();
147  if (idLen + 1U > NLOCAL)
148  buf = new char[idLen + 1U];
149  const char *from = id_.data();
150  bool inVersion = false;
151  unsigned ito = 0;
152  for (unsigned ifrom = 0; ifrom < idLen; ++ifrom) {
153  if (from[ifrom] == '(') {
154  if (inVersion) {
155  if (buf != localbuf)
156  delete[] buf;
157  return false;
158  }
159  inVersion = true;
160  } else if (from[ifrom] == ')') {
161  if (!inVersion) {
162  if (buf != localbuf)
163  delete[] buf;
164  return false;
165  }
166  inVersion = false;
167  } else if (!inVersion)
168  buf[ito++] = from[ifrom];
169  }
170  if (inVersion) {
171  if (buf != localbuf)
172  delete[] buf;
173  return false;
174  }
175  buf[ito] = '\0';
176  name_ = buf;
177  if (buf != localbuf)
178  delete[] buf;
179  return true;
180  }
181 
182  // Parse the version number and pointer switch
183  bool ClassId::makeVersion() {
184  bool correct = false;
185  const unsigned ns = id_.size();
186  const char *const buf = id_.data();
187  const char *sep = buf + (ns - 1U);
188  if (*sep == '*') {
189  isPtr_ = true;
190  --sep;
191  } else
192  isPtr_ = false;
193  if (*sep == ')') {
194  const char *closingBrace = sep;
195  for (; sep != buf; --sep)
196  if (*sep == '(')
197  break;
198  if (sep != buf) {
199  char *endptr;
200  version_ = strtoul(sep + 1, &endptr, 10);
201  if (endptr > sep + 1 && endptr == closingBrace)
202  correct = true;
203  }
204  }
205  return correct;
206  }
207 
208  ClassId::ClassId(const std::string &id) : id_(id) {
209  if (!(!id_.empty() && makeName() && makeVersion())) {
210  std::ostringstream os;
211  os << "In gs::ClassId::ClassId(const std::string&): "
212  << "invalid input id string \"" << id_ << "\"";
213  throw gs::IOInvalidArgument(os.str());
214  }
215  }
216 
217  ClassId::ClassId(std::istream &in, int) {
218  read_pod(in, &id_);
219  if (in.fail())
220  throw IOReadFailure(
221  "In gs::ClassId::ClassId(std::istream&, int): "
222  "input stream failure");
223 
224  if (!(!id_.empty() && makeName() && makeVersion())) {
225  std::ostringstream os;
226  os << "In gs::ClassId::ClassId(std::istream&, int): "
227  << "read invalid id string \"" << id_ << "\"";
228  throw IOInvalidData(os.str());
229  }
230  }
231 
232  bool ClassId::write(std::ostream &os) const {
233  write_pod(os, id_);
234  return !os.fail();
235  }
236 
237  ClassId::ClassId() : name_(""), id_("(0)"), version_(0U), isPtr_(false) {}
238 
239  ClassId ClassId::invalidId() {
240  ClassId dummy;
241  return dummy;
242  }
243 
244  bool ClassId::isTemplate() const {
245  const std::size_t leftBrak = id_.find('<');
246  const std::size_t rightBrak = id_.rfind('>');
247  return leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak;
248  }
249 
250  void ClassId::templateParameters(std::vector<std::vector<ClassId>> *params) const {
251  assert(params);
252  params->clear();
253  const std::size_t leftBrak = id_.find('<');
254  const std::size_t rightBrak = id_.rfind('>');
255  if (leftBrak != std::string::npos && rightBrak != std::string::npos && leftBrak < rightBrak) {
256  // Count commas and angle brackets
257  unsigned ncommas = 0;
258  int nbrackets = 0;
259  for (std::size_t pos = leftBrak + 1; pos < rightBrak; ++pos) {
260  const char c = id_[pos];
261  if (c == '<')
262  ++nbrackets;
263  else if (c == '>')
264  --nbrackets;
265  else if (c == ',' && nbrackets == 0)
266  ++ncommas;
267  }
268 
269  // Must be a well-formed name
270  if (nbrackets) {
271  std::ostringstream os;
272  os << "In gs::ClassId::templateParameters: "
273  << "unbalanced angle brackets in the "
274  << "template id \"" << id_ << "\"";
275  throw gs::IOInvalidArgument(os.str());
276  }
277 
278  // Reserve a proper size vector
279  params->resize(ncommas + 1);
280  for (unsigned i = 0; i <= ncommas; ++i)
281  (*params)[i].reserve(1);
282 
283  // Cycle over commas again and fill the ids
284  ncommas = 0;
285  nbrackets = 0;
286  std::size_t begin = leftBrak + 1;
287  for (std::size_t pos = begin; pos < rightBrak; ++pos) {
288  const char c = id_[pos];
289  if (c == '<')
290  ++nbrackets;
291  else if (c == '>')
292  --nbrackets;
293  else if (c == ',' && nbrackets == 0) {
294  while (isspace(id_[begin]))
295  ++begin;
296  std::size_t end = pos - 1;
297  while (isspace(id_[end]))
298  --end;
299  ++end;
300  (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
301  begin = pos + 1;
302  ++ncommas;
303  }
304  }
305  while (isspace(id_[begin]))
306  ++begin;
307  std::size_t end = rightBrak - 1;
308  while (isspace(id_[end]))
309  --end;
310  ++end;
311  (*params)[ncommas].push_back(ClassId(id_.substr(begin, end - begin)));
312  }
313  }
314 } // namespace gs
static AlgebraicMatrix initialize()
assert(be >=bs)
#define NLOCAL
Definition: ClassId.cc:13
Definition: AbsArchive.cc:46