ATLAS Offline Software
Loading...
Searching...
No Matches
CxxUtils/Root/ClassName.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
10
11
12#include "CxxUtils/ClassName.h"
13#include <cassert>
14
15
16namespace CxxUtils {
17
18
19
24 : std::runtime_error ("ExcBadClassName: Malformed class name: `" +
25 name + "'")
26{
27}
28
29
34 : std::runtime_error ("ExcMissingVariable: Variable `" + var +
35 "' referenced in substitution but not present "
36 "in matches map.")
37{
38}
39
40
45{
46 return m_rules.size();
47}
48
49
60void ClassName::Rules::add (const ClassName& pattern,
61 const ClassName& replacement)
62{
63 m_rules.insert (std::make_pair (pattern.name(),
64 std::make_pair (pattern, replacement)));
65}
66
67
79 ClassName&& replacement)
80{
81 std::string name = pattern.name();
82 m_rules.insert (std::make_pair (name,
83 std::make_pair (std::move(pattern),
84 std::move(replacement))));
85}
86
87
100{
101 bool ret = false;
102 rulemap_t::const_iterator it = m_rules.find (cn.name());
103 while (it != m_rules.end() && it->first == cn.name()) {
104 ClassName::match_t matches;
105 if (cn.match (it->second.first, matches)) {
106 bool const_save = cn.isConst();
107 cn = it->second.second.substCopy (matches);
108 if (const_save) {
109 cn.setConst();
110 }
111 ret = true;
112 }
113 ++it;
114 }
115 return ret;
116}
117
118
127std::string ClassName::Rules::apply (const std::string& name) const
128{
129 return ClassName::applyRules (name, *this);
130}
131
132
139 : m_const(false)
140{
141}
142
143
151 : m_const(false)
152{
153 std::string sname = name;
154 std::string::size_type pos = 0;
155 parse (sname, pos);
156 skipSpaces (sname, pos);
157 if (pos != sname.size())
158 throw ExcBadClassName (sname);
159}
160
161
168ClassName::ClassName (const std::string& name)
169 : m_const(false)
170{
171 std::string::size_type pos = 0;
172 parse (name, pos);
173 skipSpaces (name, pos);
174 if (pos != name.size())
175 throw ExcBadClassName (name);
176}
177
178
186ClassName::ClassName (const std::string& name, std::string::size_type& pos)
187 : m_const (false)
188{
189 parse (name, pos);
190}
191
192
198{
199 std::swap (m_const, other.m_const);
200 std::swap (m_namespace, other.m_namespace);
201 std::swap (m_name, other.m_name);
202 m_targs.swap (other.m_targs);
203}
204
205
210{
211 return m_const;
212}
213
214
219{
220 m_const = true;
221}
222
223
229const std::string& ClassName::name() const
230{
231 return m_name;
232}
233
234
240std::string ClassName::qualifiedName() const
241{
242 std::string nsname;
243 if (m_namespace.size() > 0)
244 nsname = m_namespace[0].fullName() + "::";
245 return nsname + m_name;
246}
247
248
252std::string ClassName::fullName() const
253{
254 std::string name = qualifiedName();
255 if (m_const)
256 name = "const " + name;
257 if (m_targs.size() > 0) {
258 name += '<';
259 for (const ClassName& cn : m_targs) {
260 if (name[name.size()-1] != '<')
261 name += ',';
262 name += cn.fullName();
263 }
264 if (name[name.size()-1] == '>')
265 name += ' ';
266 name += '>';
267 }
268 return name;
269}
270
271
275size_t ClassName::ntargs() const
276{
277 return m_targs.size();
278}
279
280
285const ClassName& ClassName::targ (size_t i) const
286{
287 return m_targs.at (i);
288}
289
290
294bool ClassName::operator== (const ClassName& other) const
295{
296 if (m_name != other.m_name)
297 return false;
298
299 if (m_const != other.m_const)
300 return false;
301
302 if (m_namespace.size() != other.m_namespace.size())
303 return false;
304
305 if (m_targs.size() != other.m_targs.size())
306 return false;
307
308 if (m_namespace.size() > 0 && m_namespace[0] != other.m_namespace[0])
309 return false;
310
311 for (size_t i = 0; i < m_targs.size(); ++i) {
312 if (m_targs[i] != other.m_targs[i])
313 return false;
314 }
315
316 return true;
317}
318
319
323bool ClassName::operator!= (const ClassName& other) const
324{
325 return !(*this==other);
326}
327
328
339bool ClassName::match (const ClassName& pattern, match_t& matches) const
340{
341 matches.clear();
342 return match1 (pattern, true, matches);
343}
344
345
357void ClassName::subst (const match_t& matches)
358{
359 if (m_name[0] == '$') {
360 std::string var = m_name.substr (1, std::string::npos);
361 match_t::const_iterator it = matches.find (var);
362 if (it != matches.end()) {
363 bool const_save = m_const;
364 *this = it->second;
365 m_const |= const_save;
366 }
367 else {
368 throw ExcMissingVariable (var);
369 }
370 }
371
372 for (ClassName& c : m_namespace)
373 c.subst (matches);
374 for (ClassName& c : m_targs)
375 c.subst (matches);
376}
377
378
391{
392 ClassName cn (*this);
393 cn.subst (matches);
394 return cn;
395}
396
397
410void ClassName::applyRules (const Rules& rules)
411{
412 while (applyRules1 (rules))
413 ;
414}
415
416
430std::string ClassName::applyRules (const std::string& name,
431 const Rules& rules)
432{
433 ClassName cn (name);
434 cn.applyRules (rules);
435 return cn.fullName();
436}
437
438
447void ClassName::parse (const std::string& name, std::string::size_type& pos)
448{
449 m_name = parsePrimary (name, pos);
450 if (m_name.compare (0, 6, "const ") ==0) {
451 m_const = true;
452 m_name.erase (0, 6);
453 }
454 if (m_name.size() >= 6 && m_name.compare (m_name.size()-6, 6, " const") ==0) {
455 m_const = true;
456 m_name.erase (m_name.size()-6, 6);
457 }
458
459 skipSpaces (name, pos);
460 while (pos < name.size()) {
461 if (name[pos] == '<')
462 parseTemplateArgs (name, pos);
463 else if (name[pos] == ':' && pos+1 < name.size() && name[pos+1] == ':')
464 parseNamespace (name, pos);
465 else
466 break;
467 }
468 skipSpaces (name, pos);
469 if (name.compare (pos, 5, "const")==0) {
470 m_const = true;
471 pos += 5;
472 }
473}
474
475
487std::string
488ClassName::parsePrimary (const std::string& name, std::string::size_type& pos)
489{
490 skipSpaces (name, pos);
491 std::string out;
492 size_t nest = 0;
493 while (pos < name.size()) {
494 char c = name[pos];
495 if (c == '(')
496 ++nest;
497 else if (c == ')' && nest > 0)
498 --nest;
499 else if (nest == 0 && (c == '<' || c == '>' || c == ',' || c == ':'))
500 break;
501
502 out += c;
503 ++pos;
504 }
505 return out;
506}
507
508
522void ClassName::parseNamespace (const std::string& name,
523 std::string::size_type& pos)
524{
525 assert (pos+1 < name.size() && name[pos] == ':' && name[pos+1] == ':');
526 pos += 2;
527 skipSpaces (name, pos);
528
529 ClassName ns (name, pos);
530 ns.swap (*this);
531 if (ns.isConst()) {
532 this->setConst();
533 ns.m_const = false;
534 }
535 ClassName* p = this;
536 while (p->m_namespace.size() > 0)
537 p = &p->m_namespace[0];
538 p->m_namespace.push_back (std::move(ns));
539}
540
541
554void ClassName::parseTemplateArgs (const std::string& name,
555 std::string::size_type& pos)
556{
557 assert (pos < name.size() && name[pos] == '<');
558 ++pos;
559 while (true) {
560 skipSpaces (name, pos);
561 m_targs.emplace_back (name, pos);
562 skipSpaces (name, pos);
563 if (pos == name.size()) break;
564 if (name[pos] == '>') {
565 ++pos;
566 break;
567 }
568 else if (name[pos] == ',')
569 ++pos;
570 else
571 break;
572 }
573}
574
575
584void ClassName::skipSpaces (const std::string& name,
585 std::string::size_type& pos)
586{
587 while (pos < name.size() && name[pos] == ' ')
588 ++pos;
589}
590
591
603bool ClassName::match1 (const ClassName& pattern,
604 bool topLevel,
605 match_t& matches) const
606{
607 if (pattern.m_name[0] == '$') {
608 std::string var = pattern.m_name.substr (1, std::string::npos);
609 match_t::iterator it = matches.find (var);
610 if (it != matches.end()) {
611 if (pattern.m_const && !it->second.m_const) {
612 ClassName cn (it->second);
613 cn.setConst();
614 return *this == cn;
615 }
616 return *this == it->second;
617 }
618
619 matches[var] = *this;
620 if (pattern.m_const) {
621 if (m_const)
622 matches[var].m_const = false;
623 else
624 return false;
625 }
626 return true;
627 }
628
629 // Require that const qualifiers match.
630 // However, if this is the top level, we allow a pattern with no explicit
631 // const to match something that is const. Otherwise, we'd need to repeat
632 // all patterns for the const case.
633 if (topLevel) {
634 if (pattern.m_const && !m_const)
635 return false;
636 }
637 else if (m_const != pattern.m_const) {
638 return false;
639 }
640
641 if (m_name != pattern.m_name)
642 return false;
643
644 if (m_namespace.size() != pattern.m_namespace.size())
645 return false;
646
647 if (m_targs.size() != pattern.m_targs.size())
648 return false;
649
650 if (m_namespace.size() > 0) {
651 if (!m_namespace[0].match1 (pattern.m_namespace[0], false, matches))
652 return false;
653 }
654
655 for (size_t i = 0; i < m_targs.size(); i++) {
656 if (!m_targs[i].match1 (pattern.m_targs[i], false, matches))
657 return false;
658 }
659
660 return true;
661}
662
663
674bool ClassName::applyRules1 (const Rules& rules)
675{
676 bool ret = rules.applyTo (*this);
677
678 if (m_namespace.size() > 0)
679 ret |= m_namespace[0].applyRules1 (rules);
680
681 for (size_t i = 0; i < m_targs.size(); i++)
682 ret |= m_targs[i].applyRules1 (rules);
683
684 return ret;
685}
686
687
688} // namespace CxxUtils
689
Recursively separate out template arguments in a C++ class name.
Exception to signal a malformed class name.
ExcBadClassName(const std::string &name)
Exception to signal a malformed class name.
Exception to signal a missing variable.
ExcMissingVariable(const std::string &var)
Exception to signal a missing variable.
A set of transformation rules to use with ClassName.
std::string apply(const std::string &name) const
Apply transformations to a class name.
void add(const ClassName &pattern, const ClassName &replacement)
Add a new transformation rule.
bool applyTo(ClassName &cn) const
Apply the set of transformation rules to a class name object.
size_t size() const
Return the number of defined rules.
bool operator==(const ClassName &other) const
Test two expressions for equality.
bool match1(const ClassName &pattern, bool topLevel, match_t &matches) const
Match this expression against a pattern.
bool isConst() const
Get the const flag for this expression.
std::vector< ClassName > m_namespace
The containing namespace.
void subst(const match_t &matches)
Substitute variables into this expression.
std::string parsePrimary(const std::string &name, std::string::size_type &pos)
Parse a primary part of the class name.
bool m_const
Is this expression const?
void skipSpaces(const std::string &name, std::string::size_type &pos)
Skip past spaces in a string.
std::string m_name
The primary name part of this expression.
std::string fullName() const
Return the full name of the expression.
bool operator!=(const ClassName &other) const
Test two expressions for inequality.
std::vector< ClassName > m_targs
The template arguments for this name.
bool applyRules1(const Rules &rules)
Apply a set of transformation rules to this object.
ClassName substCopy(const match_t &matches) const
Return a copy of this expression with variables substituted.
std::map< std::string, ClassName > match_t
Map used to hold variable assignments from matching.
ClassName()
Default constructor.
const std::string & name() const
Return the root name of the expression.
bool match(const ClassName &pattern, match_t &matches) const
Match this expression against a pattern.
const ClassName & targ(size_t i) const
Return one template argument.
std::string qualifiedName() const
Return the namespace-qualified name of the expression.
void setConst()
Set the const flag for this expression.
void applyRules(const Rules &rules)
Apply a set of transformation rules to this object.
void parseNamespace(const std::string &name, std::string::size_type &pos)
Parse a namespace qualification.
void swap(ClassName &other)
Swap this expression with another one.
void parse(const std::string &name, std::string::size_type &pos)
Parse a string into a ClassName.
void parseTemplateArgs(const std::string &name, std::string::size_type &pos)
Parse the template part of a name.
size_t ntargs() const
Return number of template arguments.
STL class.
STL namespace.
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)