LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
maybeCastObj.cc
Go to the documentation of this file.
2 // vim: set sw=2:
3 
5 #include "cetlib_except/demangle.h"
6 
7 #include <cxxabi.h>
8 
9 #ifdef _LIBCPPABI_VERSION
10 #include "TClass.h"
11 #include "TClassRef.h"
12 #endif
13 
14 #include <iomanip>
15 #include <iostream>
16 #include <typeinfo>
17 
18 using namespace art;
19 using namespace std;
20 
21 #ifdef _LIBCPPABI_VERSION
22 
23 bool
24 detail::upcastAllowed(type_info const& tid_from, type_info const& tid_to)
25 {
26  if (tid_from == tid_to) {
27  return true;
28  }
29  auto const clFrom = TClass::GetClass(tid_from);
30  if (!clFrom) {
31  return false;
32  }
33  auto const clTo = TClass::GetClass(tid_to);
34  if (!clTo) {
35  return false;
36  }
37  return clFrom->InheritsFrom(clTo);
38 }
39 
40 void const*
41 art::detail::maybeCastObj(void const* address,
42  std::type_info const& tiFrom,
43  std::type_info const& tiTo)
44 {
45  if (tiFrom == tiTo) {
46  // The do nothing case.
47  return address;
48  }
49  auto const clFrom = TClass::GetClass(tiFrom);
50  auto const clTo = TClass::GetClass(tiTo);
51  if (clFrom && clTo) {
52  void const* castAddr(nullptr);
53  if (clFrom->InheritsFrom(clTo)) {
54  // The upcast case, let ROOT do it.
55  castAddr = clFrom->DynamicCast(clTo, const_cast<void*>(address), true);
56  } else if (clTo->InheritsFrom(clFrom)) {
57  // The downcast case is forbidden.
59  << "art::Wrapper<> : unable to convert type "
60  << cet::demangle_symbol(tiFrom.name()) << " to "
61  << cet::demangle_symbol(tiTo.name()) << ", which is a subclass.\n";
62  }
63  if (castAddr != nullptr) {
64  // ROOT succeeded, done.
65  return castAddr;
66  }
67  }
68  // ROOT could not do the upcast, or there was no inheritance
69  // relationship between the classes, die.
71  << "art::Wrapper<> : unable to convert type "
72  << cet::demangle_symbol(tiFrom.name()) << " to "
73  << cet::demangle_symbol(tiTo.name()) << "\n";
74 }
75 
76 #else // _LIBCPPABI_VERSION
77 
78 namespace {
79 
80  class upcast_result {
81  public:
82  bool first_call = true;
83  bool found = false;
84  bool is_ambiguous = false;
85  long offset = 0L;
86 
87  public:
88  void print[[gnu::unused]]() const;
89  void reset[[gnu::unused]]();
90  };
91 
92  void
93  upcast_result::print() const
94  {
95  cout << " found: " << found << endl;
96  cout << "is_ambiguous: " << is_ambiguous << endl;
97  cout << " offset: " << offset << endl;
98  }
99 
100  void
101  upcast_result::reset()
102  {
103  first_call = true;
104  found = false;
105  is_ambiguous = false;
106  offset = 0L;
107  }
108 
109  void
110  visit_class_for_upcast(abi::__class_type_info const* ci,
111  abi::__class_type_info const* dest,
112  long offset,
113  upcast_result& res)
114  {
115  if (res.first_call) {
116  res.first_call = false;
117  } else if (ci == dest) {
118  // We found a possible answer.
119  if (!res.found) {
120  res.found = true;
121  res.offset = offset;
122  } else {
123  res.is_ambiguous = true;
124  }
125  }
126  // Visit bases, if any.
127  if (auto si = dynamic_cast<abi::__si_class_type_info const*>(ci)) {
128  // Class is part of a public non-virtual single inheritance chain.
129  visit_class_for_upcast(si->__base_type, dest, offset, res);
130  return;
131  }
132  if (auto vmi = dynamic_cast<abi::__vmi_class_type_info const*>(ci)) {
133  // Class is part of a more complicated inheritance chain.
134  for (auto i = 0U; i < vmi->__base_count; ++i) {
135  auto const& base = vmi->__base_info[i];
136  bool is_public = false;
137  if (base.__offset_flags & abi::__base_class_type_info::__public_mask) {
138  is_public = true;
139  }
140  long boff =
141  (base.__offset_flags >> abi::__base_class_type_info::__offset_shift);
142  if (is_public && (boff > -1)) {
143  // Base is public access, and boff is not the offset to the
144  // virtual base offset.
145  visit_class_for_upcast(base.__base_type, dest, offset + boff, res);
146  }
147  }
148  return;
149  }
150  // Was a leaf class.
151  }
152 
153 } // unnamed namespace
154 
155 bool
156 detail::upcastAllowed(type_info const& tid_from, type_info const& tid_to)
157 {
158  if (tid_from == tid_to) {
159  // Trivial, nothing to do.
160  return true;
161  }
162  auto ci_from = dynamic_cast<abi::__class_type_info const*>(&tid_from);
163  auto ci_to = dynamic_cast<abi::__class_type_info const*>(&tid_to);
164  if (ci_from == nullptr) {
165  // Not a class, done.
166  return false;
167  }
168  if (ci_to == nullptr) {
169  // Not a class, done.
170  return false;
171  }
172  if (ci_from == ci_to) {
173  // Trivial, same types, nothing to do.
174  return true;
175  }
176  upcast_result res;
177  visit_class_for_upcast(ci_from, ci_to, 0L, res);
178  return res.found && !res.is_ambiguous;
179 }
180 
181 void const*
182 detail::maybeCastObj(void const* ptr,
183  type_info const& tid_from,
184  type_info const& tid_to)
185 {
186  if (tid_from == tid_to) {
187  // Trivial, nothing to do.
188  return ptr;
189  }
190  auto ci_from = dynamic_cast<abi::__class_type_info const*>(&tid_from);
191  auto ci_to = dynamic_cast<abi::__class_type_info const*>(&tid_to);
192  if (ci_from == nullptr) {
193  // Not a class, done.
194  return ptr;
195  }
196  if (ci_to == nullptr) {
197  // Not a class, done.
198  return ptr;
199  }
200  if (ci_from == ci_to) {
201  // Trivial, same types, nothing to do.
202  return ptr;
203  }
204  upcast_result res;
205  visit_class_for_upcast(ci_from, ci_to, 0L, res);
206  if (!res.found) {
208  << "maybeCastObj : unable to convert type: "
209  << cet::demangle_symbol(tid_from.name())
210  << "\nto: " << cet::demangle_symbol(tid_to.name()) << "\n"
211  << "No suitable base found.\n";
212  }
213  if (res.is_ambiguous) {
215  << "MaybeCastObj : unable to convert type: "
216  << cet::demangle_symbol(tid_from.name())
217  << "\nto: " << cet::demangle_symbol(tid_to.name()) << "\n"
218  << "Base class is ambiguous.\n";
219  }
220  return static_cast<char const*>(ptr) + res.offset;
221 }
222 
223 #endif // _LIBCPPABI_VERSION
void const * maybeCastObj(element_type const *address, std::type_info const &tiTo)
Definition: maybeCastObj.h:21
STL namespace.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
HLT enums.
bool upcastAllowed(std::type_info const &tiFrom, std::type_info const &tiTo)