CMS 3D CMS Logo

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