Panda3D
Loading...
Searching...
No Matches
typeRegistryNode.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file typeRegistryNode.cxx
10 * @author drose
11 * @date 2001-08-06
12 */
13
14#include "typeRegistryNode.h"
15
16#include <algorithm>
17#include <string.h>
18
19bool TypeRegistryNode::_paranoid_inheritance = false;
20
21/**
22 *
23 */
24TypeRegistryNode::
25TypeRegistryNode(TypeHandle handle, const std::string &name, TypeHandle &ref) :
26 _handle(handle), _name(name), _ref(ref)
27{
28 clear_subtree();
29 memset(_memory_usage, 0, sizeof(_memory_usage));
30}
31
32/**
33 * Returns true if the child RegistryNode represents a class that inherits
34 * directly or indirectly from the class represented by the base RegistryNode.
35 */
37is_derived_from(const TypeRegistryNode *child, const TypeRegistryNode *base) {
38 // This function is the basis for TypedObject::is_of_type(), which gets used
39 // quite frequently within Panda, often in inner-loop code. Therefore, we
40 // go through some pains to make this function as efficient as possible.
41
42 // First, compare the subtree tops. If they are the same, then this node
43 // and the base node are within the same single-inheritance subtree, and we
44 // can use our bitmask trick to determine the relationship with no
45 // additional work. (See r_build_subtrees()).
46
47 if (child->_inherit._top == base->_inherit._top) {
48 assert(child->_inherit._top != nullptr);
49
50 bool derives =
51 Inherit::is_derived_from(child->_inherit, base->_inherit);
52
53#ifndef NDEBUG
54 if (_paranoid_inheritance) {
55 bool paranoid_derives = check_derived_from(child, base);
56 if (derives != paranoid_derives) {
57 std::cerr
58 << "Inheritance test for " << child->_name
59 << " from " << base->_name << " failed!\n"
60 << "Result: " << derives << " should have been: "
61 << paranoid_derives << "\n"
62 << "Classes are in the same single inheritance subtree, children of "
63 << child->_inherit._top->_name << "\n"
64 << std::hex
65 << child->_name << " has mask " << child->_inherit._mask
66 << " and bits " << child->_inherit._bits << "\n"
67 << base->_name << " has mask " << base->_inherit._mask
68 << " and bits " << base->_inherit._bits << "\n"
69 << std::dec;
70 return paranoid_derives;
71 }
72 }
73#endif
74
75 /*
76 cerr << "trivial: " << child->_name << " vs. " << base->_name
77 << " (" << child->_inherit._top->_name << ") = " << derives << "\n";
78 */
79
80 return derives;
81 }
82
83 // The two nodes are not within the same single-inheritance subtree. This
84 // complicates things a bit.
85
86 // First, we should check whether the subtree tops of the two nodes inherit
87 // from each other.
88 TypeRegistryNode *child_top = child->_inherit._top;
89 TypeRegistryNode *base_top = base->_inherit._top;
90
91 bool derives = false;
92
93 // If child_top does not inherit from base_top, it follows that child does
94 // not inherit from base.
95 TopInheritance::const_iterator ti =
96 lower_bound(child_top->_top_inheritance.begin(),
97 child_top->_top_inheritance.end(),
98 Inherit(base_top, 0, 0));
99
100 while (ti != child_top->_top_inheritance.end() &&
101 (*ti)._top == base_top &&
102 !derives) {
103 // If child_top *does* inherit from base_top, then child may or may not
104 // inherit from base. This depends on the exact path of inheritance.
105 // Since there might be multiple paths from child_top to base_top, we have
106 // to examine all of them.
107 const Inherit &connection = (*ti);
108
109 // Here is one inheritance from child_top to base_top. If the connecting
110 // node inherits from base, then child also inherits from base. If the
111 // connecting node does not inherit from base, we must keep looking.
112 derives = Inherit::is_derived_from(connection, base->_inherit);
113
114 ++ti;
115 }
116
117#ifndef NDEBUG
118 if (_paranoid_inheritance) {
119 bool paranoid_derives = check_derived_from(child, base);
120 if (derives != paranoid_derives) {
121 std::cerr
122 << "Inheritance test for " << child->_name
123 << " from " << base->_name << " failed!\n"
124 << "Result: " << derives << " should have been: "
125 << paranoid_derives << "\n"
126 << child->_name << " is a descendent of "
127 << child_top->_name << "\n"
128 << base->_name << " is a descendent of "
129 << base_top->_name << "\n";
130 return paranoid_derives;
131 }
132 }
133#endif
134
135 /*
136 cerr << "complex: " << child->_name << " (" << child->_inherit._top->_name
137 << ") vs. " << base->_name << " (" << base->_inherit._top->_name
138 << ") = " << derives << "\n";
139 */
140 return derives;
141}
142
143/**
144 * Returns the first parent class of child that is a descendant of the
145 * indicated base class.
146 */
149 const TypeRegistryNode *base) {
150 if (child == base) {
151 return child->_handle;
152 }
153
154 Classes::const_iterator ni;
155 for (ni = child->_parent_classes.begin();
156 ni != child->_parent_classes.end(); ++ni) {
157 if (is_derived_from((*ni), base)) {
158 return (*ni)->_handle;
159 }
160 }
161
162 return TypeHandle::none();
163}
164
165
166/**
167 * Removes any subtree definition previously set up via define_subtree(), in
168 * preparation for rebuilding the subtree data.
169 */
172 _inherit = Inherit();
173 _top_inheritance.clear();
174 _visit_count = 0;
175}
176
177/**
178 * Indicates that this TypeRegistryNode is the top of a subtree within the
179 * inheritance graph (typically, this indicates a multiple-inheritance node).
180 * Builds all the subtree_mask etc. flags for nodes at this level and below.
181 */
184 // cerr << "Building subtree for " << _name << ", top inheritance is:\n";
185
186 /*
187 TopInheritance::const_iterator ti;
188 for (ti = _top_inheritance.begin(); ti != _top_inheritance.end(); ++ti) {
189 const Inherit &t = (*ti);
190 cerr << " from " << t._top->_name << " via "
191 << hex << t._bits << " / " << t._mask << dec << "\n";
192 }
193 */
194
195 r_build_subtrees(this, 0, 0);
196}
197
198/**
199 * Recursively builds up all the subtree cache information for this node and
200 * the ones below. This information is used to quickly determine class
201 * inheritance.
202 */
203void TypeRegistryNode::
204r_build_subtrees(TypeRegistryNode *top, int bit_count,
205 TypeRegistryNode::SubtreeMaskType bits) {
206 // The idea with these bits is to optimize the common case of a single-
207 // inheritance graph (that is, an inheritance tree), or a single-inheritance
208 // subgraph of the full multiple-inheritance graph (i.e. a subtree of the
209 // inheritance graph).
210
211/*
212 * When we have just single inheritance, we can define a unique number for
213 * each node in the inheritance tree that allows us to immediately determine
214 * the inheritance relationship between any two nodes in the tree. We choose
215 * a number such that for a given node whose number has n bits, each child
216 * node has m + n bits where the low-order n bits are the same as the parent
217 * node's bits, and the high-order m bits are unique among each sibling. The
218 * node at the top of the tree has zero bits.
219 */
220
221 // That way, we can simply compare bitmasks to determine if class A inherits
222 // from class B. If the low-order bits are the same, they have some
223 // ancestry in common. The highest-order bit that still matches corresponds
224 // to the lowest node in the tree that they have in common; i.e. the node
225 // from which they both inherit.
226
227 // To put it more formally, let count(A) be the number of bits in A's
228 // number, and count(B) be the number of bits in B's number. A inherits
229 // from B if and only if count(B) <= count(A), and the lower count(B) bits
230 // of A's number are the same as those in B's number.
231
232 // This algorithm breaks down in the presence of multiple inheritance, since
233 // we can't make up a single number for each node any more. We still take
234 // advantage of the algorithm by considering each single-inheritance
235 // subgraph separately.
236
237 // To handle multiple inheritance, we reset the numbers to zero every time
238 // we come across a multiple-inheritance node (this begins a new subtree).
239 // There are relatively few of these "subtree top" nodes, and we record the
240 // explicit inheritance of each one from all of its ancestor "subtree top"
241 // nodes within the node itself.
242
243 if (top != this && _parent_classes.size() != 1) {
244 assert(!_parent_classes.empty());
245
246 // This class multiply inherits; it therefore begins a new subtree.
247
248 // Copy in the inheritance relations from our parent subtree tops.
249 _top_inheritance.insert(_top_inheritance.end(),
250 top->_top_inheritance.begin(),
251 top->_top_inheritance.end());
252 _top_inheritance.push_back(Inherit(top, bit_count, bits));
253
254 _visit_count++;
255 if (_visit_count == (int)_parent_classes.size()) {
256 // This is the last time we'll visit this node, so continue the
257 // recursion now.
258 assert(_inherit._top == nullptr);
259 sort(_top_inheritance.begin(), _top_inheritance.end());
261 }
262
263 } else {
264 // This class singly inherits, so this had better be the only time this
265 // function is called on it since clear_subtree().
266 assert(_inherit._top == nullptr);
267
268 assert(bit_count < (int)(sizeof(SubtreeMaskType) * 8));
269
270 _inherit = Inherit(top, bit_count, bits);
271
272 // Now, how many more bits do we need to encode each of our children?
273 int num_children = (int)_child_classes.size();
274 int more_bits = 0;
275 int i = num_children - 1;
276 while (i > 0) {
277 more_bits++;
278 i >>= 1;
279 }
280
281 // We need at least one bit, even if there is only one child, so we can
282 // differentiate parent from child.
283 more_bits = std::max(more_bits, 1);
284
285 assert(more_bits < (int)(sizeof(SubtreeMaskType) * 8));
286
287 if (bit_count + more_bits > (int)(sizeof(SubtreeMaskType) * 8)) {
288 // Too many bits; we need to start a new subtree right here. This node
289 // becomes a subtree top node, even though it's not a multiple-
290 // inheritance node.
291 assert(top != this);
292 _top_inheritance = top->_top_inheritance;
293 _top_inheritance.push_back(_inherit);
294 sort(_top_inheritance.begin(), _top_inheritance.end());
295 _inherit = Inherit();
297
298 } else {
299 // Still plenty of bits, so keep going.
300 for (i = 0; i < num_children; i++) {
301 TypeRegistryNode *child = _child_classes[i];
302 SubtreeMaskType next_bits = ((SubtreeMaskType)i << bit_count);
303
304 child->r_build_subtrees(top, bit_count + more_bits,
305 bits | next_bits);
306 }
307 }
308 }
309}
310
311/**
312 * Recurses through the parent nodes to find the best Python type object to
313 * represent objects of this type.
314 */
315PyObject *TypeRegistryNode::
316r_get_python_type() const {
317 Classes::const_iterator ni;
318 for (ni = _parent_classes.begin(); ni != _parent_classes.end(); ++ni) {
319 const TypeRegistryNode *parent = *ni;
320 if (parent->_python_type != nullptr) {
321 return parent->_python_type;
322
323 } else if (!parent->_parent_classes.empty()) {
324 PyObject *py_type = parent->r_get_python_type();
325 if (py_type != nullptr) {
326 return py_type;
327 }
328 }
329 }
330
331 return nullptr;
332}
333
334/**
335 * A recursive function to double-check the result of is_derived_from(). This
336 * is the slow, examine-the-whole-graph approach, as opposed to the clever and
337 * optimal algorithm of is_derived_from(); it's intended to be used only for
338 * debugging said clever algorithm.
339 */
340bool TypeRegistryNode::
341check_derived_from(const TypeRegistryNode *child,
342 const TypeRegistryNode *base) {
343 if (child == base) {
344 return true;
345 }
346
347 Classes::const_iterator ni;
348 for (ni = child->_parent_classes.begin();
349 ni != child->_parent_classes.end();
350 ++ni) {
351 if (check_derived_from(*ni, base)) {
352 return true;
353 }
354 }
355
356 return false;
357}
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is a single entry in the TypeRegistry.
static bool is_derived_from(const TypeRegistryNode *child, const TypeRegistryNode *base)
Returns true if the child RegistryNode represents a class that inherits directly or indirectly from t...
void clear_subtree()
Removes any subtree definition previously set up via define_subtree(), in preparation for rebuilding ...
static TypeHandle get_parent_towards(const TypeRegistryNode *child, const TypeRegistryNode *base)
Returns the first parent class of child that is a descendant of the indicated base class.
void define_subtree()
Indicates that this TypeRegistryNode is the top of a subtree within the inheritance graph (typically,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.