Panda3D
typeRegistry.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 typeRegistry.cxx
10  * @author drose
11  * @date 2001-08-06
12  */
13 
14 #include "typeRegistry.h"
15 #include "typeRegistryNode.h"
16 #include "typeHandle.h"
17 #include "typedObject.h"
18 #include "indent.h"
19 #include "numeric_types.h"
20 
21 #include <algorithm>
22 
23 using std::cerr;
24 using std::ostream;
25 using std::ostringstream;
26 using std::string;
27 
28 MutexImpl *TypeRegistry::_lock = nullptr;
29 TypeRegistry *TypeRegistry::_global_pointer = nullptr;
30 
31 /**
32  * Creates a new Type of the given name and assigns a unique value to the
33  * type_handle. All type names must be unique. If the type name has already
34  * been used, the supplied type_handle value must match the name's assigned
35  * type_handle or an error is triggered. Returns true if the name wasn't
36  * defined before, false if it was.
37  */
38 bool TypeRegistry::
39 register_type(TypeHandle &type_handle, const string &name) {
40  _lock->lock();
41 
42  if (type_handle != TypeHandle::none()) {
43  // Here's a type that was already registered. Just make sure everything's
44  // still kosher.
45  TypeRegistryNode *rnode = look_up(type_handle, nullptr);
46  if (&type_handle == &rnode->_ref) {
47  // No problem.
48  _lock->unlock();
49  assert(rnode->_name == name);
50  return false;
51  }
52  }
53 
54  NameRegistry::iterator ri;
55  ri = _name_registry.find(name);
56 
57  if (ri == _name_registry.end()) {
58  // The name was not already used; this is the first time this class has
59  // been defined.
60 
61  TypeHandle new_handle;
62  new_handle._index = (int)_handle_registry.size();
63 
64  TypeRegistryNode *rnode = new TypeRegistryNode(new_handle, name, type_handle);
65  _handle_registry.push_back(rnode);
66  _name_registry[name] = rnode;
67  _derivations_fresh = false;
68 
69  type_handle = new_handle;
70  _lock->unlock();
71  return true;
72  }
73  TypeRegistryNode *rnode = (*ri).second;
74  assert(rnode->_name == (*ri).first);
75  assert(rnode->_handle._index >= 0 &&
76  rnode->_handle._index < (int)_handle_registry.size());
77  assert(_handle_registry[rnode->_handle._index] == rnode);
78  assert(rnode->_handle._index != 0);
79 
80  // The name was previously used; make sure the type_handle matches.
81  if (&type_handle == &rnode->_ref) {
82  // Ok, this was just a repeated attempt to register the same type.
83 
84  if (type_handle == rnode->_handle) {
85  // No problem.
86  _lock->unlock();
87  return false;
88  }
89  // But wait--the type_handle has changed! We kept a reference to the
90  // static _type_handle member in the class that was passed in at the first
91  // call to register_type(), and we got the same reference passed in this
92  // time, but now it's different! Bad juju.
93  cerr << "Reregistering " << name << "\n";
94  type_handle = rnode->_handle;
95  _lock->unlock();
96  return false;
97  }
98 
99  if (type_handle != rnode->_handle) {
100  // Hmm, we seem to have a contradictory type registration!
101  cerr
102  << "Attempt to register type " << name << " more than once!\n";
103 
104  // This is invalid, but we'll allow it anyway. It seems to happen for
105  // some reason under GNU libc5 that we occasionally end up with two
106  // legitimate copies of the same class object in memory--each with its own
107  // static _type_handle member.
108 
109  type_handle = rnode->_handle;
110  }
111  _lock->unlock();
112  return false;
113 }
114 
115 /**
116  * Registers a new type on-the-fly, presumably at runtime. A new TypeHandle
117  * is returned if the typename was not seen before; otherwise the same
118  * TypeHandle that was last used for this typename is returned.
119  */
121 register_dynamic_type(const string &name) {
122  _lock->lock();
123 
124  NameRegistry::iterator ri;
125  ri = _name_registry.find(name);
126 
127  if (ri == _name_registry.end()) {
128  // The name was not already used; this is the first time this class has
129  // been defined.
130 
131  // We must dynamically allocate a new handle so the TypeRegistryNode has
132  // something unique to point to. This doesn't really mean anything,
133  // though.
134  TypeHandle *new_handle = new TypeHandle;
135  new_handle->_index = (int)_handle_registry.size();
136 
137  TypeRegistryNode *rnode = new TypeRegistryNode(*new_handle, name, *new_handle);
138  _handle_registry.push_back(rnode);
139  _name_registry[name] = rnode;
140  _derivations_fresh = false;
141 
142  _lock->unlock();
143  return *new_handle;
144  }
145 
146  // Return the TypeHandle previously obtained.
147  TypeRegistryNode *rnode = (*ri).second;
148  TypeHandle handle = rnode->_handle;
149  _lock->unlock();
150  return handle;
151 }
152 
153 /**
154  * Records that the type referenced by child inherits directly from the type
155  * referenced by parent. In the event of multiple inheritance, this should be
156  * called once for each parent class.
157  */
158 void TypeRegistry::
160  _lock->lock();
161 
162  TypeRegistryNode *cnode = look_up(child, nullptr);
163  assert(cnode != nullptr);
164  TypeRegistryNode *pnode = look_up(parent, nullptr);
165  assert(pnode != nullptr);
166 
167  // First, we'll just run through the list to make sure we hadn't already
168  // made this connection.
169  TypeRegistryNode::Classes::iterator ni;
170  ni = find(cnode->_parent_classes.begin(), cnode->_parent_classes.end(),
171  pnode);
172 
173  if (ni == cnode->_parent_classes.end()) {
174  cnode->_parent_classes.push_back(pnode);
175  pnode->_child_classes.push_back(cnode);
176  _derivations_fresh = false;
177  }
178 
179  _lock->unlock();
180 }
181 
182 /**
183  * Indicates an alternate name for the same type. This is particularly useful
184  * when a type has changed names, since the type is stored in a Bam file by
185  * name; setting the original name as the alternate will allow the type to be
186  * correctly read from old Bam files.
187  */
188 void TypeRegistry::
189 record_alternate_name(TypeHandle type, const string &name) {
190  _lock->lock();
191 
192  TypeRegistryNode *rnode = look_up(type, nullptr);
193  if (rnode != nullptr) {
194  NameRegistry::iterator ri =
195  _name_registry.insert(NameRegistry::value_type(name, rnode)).first;
196 
197  if ((*ri).second != rnode) {
198  _lock->unlock();
199  cerr
200  << "Name " << name << " already assigned to TypeHandle "
201  << rnode->_name << "; cannot reassign to " << type << "\n";
202  return;
203  }
204 
205  }
206 
207  _lock->unlock();
208 }
209 
210 #ifdef HAVE_PYTHON
211 /**
212  * Records the given Python type pointer in the type registry for the benefit
213  * of interrogate.
214  */
215 void TypeRegistry::
216 record_python_type(TypeHandle type, PyObject *python_type) {
217  _lock->lock();
218 
219  TypeRegistryNode *rnode = look_up(type, nullptr);
220  if (rnode != nullptr) {
221  rnode->_python_type = python_type;
222  }
223 
224  _lock->unlock();
225 }
226 #endif
227 
228 /**
229  * Looks for a previously-registered type of the given name. Returns its
230  * TypeHandle if it exists, or TypeHandle::none() if there is no such type.
231  */
233 find_type(const string &name) const {
234  _lock->lock();
235 
236  TypeHandle handle = TypeHandle::none();
237  NameRegistry::const_iterator ri;
238  ri = _name_registry.find(name);
239  if (ri != _name_registry.end()) {
240  handle = (*ri).second->_handle;
241  }
242  _lock->unlock();
243 
244  return handle;
245 }
246 
247 /**
248  * Looks for a previously-registered type with the given id number (as
249  * returned by TypeHandle::get_index()). Returns its TypeHandle if it exists,
250  * or TypeHandle::none() if there is no such type.
251  */
253 find_type_by_id(int id) const {
254  if (id < 0 ||id >= (int)_handle_registry.size()) {
255  cerr
256  << "Invalid TypeHandle index " << id
257  << "! Is memory corrupt?\n";
258  return TypeHandle::none();
259  }
260 
261  return _handle_registry[id]->_handle;
262 }
263 
264 
265 /**
266  * Returns the name of the indicated type.
267  *
268  * The "object" pointer is an optional pointer to the TypedObject class that
269  * owns this TypeHandle. It is only used in case the TypeHandle is
270  * inadvertantly undefined.
271  */
272 string TypeRegistry::
273 get_name(TypeHandle type, TypedObject *object) const {
274  _lock->lock();
275  TypeRegistryNode *rnode = look_up(type, object);
276  assert(rnode != nullptr);
277  string name = rnode->_name;
278  _lock->unlock();
279 
280  return name;
281 }
282 
283 /**
284  * Returns true if the first type is derived from the second type, false
285  * otherwise.
286  *
287  * The "child_object" pointer is an optional pointer to the TypedObject class
288  * that owns the child TypeHandle. It is only used in case the TypeHandle is
289  * inadvertently undefined.
290  *
291  * This function definition follows the definitions for look_up() and
292  * freshen_derivations() just to maximize the chance the the compiler will be
293  * able to inline the above functions. Yeah, a compiler shouldn't care, but
294  * there's a big different between "shouldn't" and "doesn't".
295  */
296 bool TypeRegistry::
298  TypedObject *child_object) {
299  _lock->lock();
300 
301  const TypeRegistryNode *child_node = look_up(child, child_object);
302  const TypeRegistryNode *base_node = look_up(base, nullptr);
303 
304  assert(child_node != nullptr);
305  assert(base_node != nullptr);
306 
307  freshen_derivations();
308 
309  bool result = TypeRegistryNode::is_derived_from(child_node, base_node);
310  _lock->unlock();
311  return result;
312 }
313 
314 /**
315  * Returns the total number of unique TypeHandles in the system.
316  */
317 int TypeRegistry::
318 get_num_typehandles() {
319  _lock->lock();
320  int num_types = (int)_handle_registry.size();
321  _lock->unlock();
322  return num_types;
323 }
324 
325 /**
326  * Returns the nth TypeHandle in the system. See get_num_typehandles().
327  */
329 get_typehandle(int n) {
330  _lock->lock();
331  TypeRegistryNode *rnode = nullptr;
332  if (n >= 0 && n < (int)_handle_registry.size()) {
333  rnode = _handle_registry[n];
334  }
335  _lock->unlock();
336 
337  if (rnode != nullptr) {
338  return rnode->_handle;
339  }
340 
341  return TypeHandle::none();
342 }
343 
344 /**
345  * Returns the number of root classes--that is, classes that do not inherit
346  * from any other classes--known in the system.
347  */
348 int TypeRegistry::
349 get_num_root_classes() {
350  _lock->lock();
351  freshen_derivations();
352  int num_roots = (int)_root_classes.size();
353  _lock->unlock();
354  return num_roots;
355 }
356 
357 /**
358  * Returns the nth root class in the system. See get_num_root_classes().
359  */
361 get_root_class(int n) {
362  _lock->lock();
363  freshen_derivations();
364  TypeHandle handle;
365  if (n >= 0 && n < (int)_root_classes.size()) {
366  handle = _root_classes[n]->_handle;
367  } else {
368  handle = TypeHandle::none();
369  }
370  _lock->unlock();
371 
372  return handle;
373 }
374 
375 /**
376  * Returns the number of parent classes that the indicated type is known to
377  * have. This may then be used to index into get_parent_class(). The result
378  * will be 0 if this class does not inherit from any other classes, 1 if
379  * normal, single inheritance is in effect, or greater than one if multiple
380  * inheritance is in effect.
381  *
382  * The "object" pointer is an optional pointer to the TypedObject class that
383  * owns this TypeHandle. It is only used in case the TypeHandle is
384  * inadvertantly undefined.
385  */
386 int TypeRegistry::
387 get_num_parent_classes(TypeHandle child, TypedObject *child_object) const {
388  _lock->lock();
389  TypeRegistryNode *rnode = look_up(child, child_object);
390  assert(rnode != nullptr);
391  int num_parents = (int)rnode->_parent_classes.size();
392  _lock->unlock();
393  return num_parents;
394 }
395 
396 /**
397  * Returns the nth parent class of this type. The index should be in the
398  * range 0 <= index < get_num_parent_classes().
399  */
401 get_parent_class(TypeHandle child, int index) const {
402  _lock->lock();
403  TypeHandle handle;
404  TypeRegistryNode *rnode = look_up(child, nullptr);
405  assert(rnode != nullptr);
406  if (index >= 0 && index < (int)rnode->_parent_classes.size()) {
407  handle = rnode->_parent_classes[index]->_handle;
408  } else {
409  handle = TypeHandle::none();
410  }
411  _lock->unlock();
412  return handle;
413 }
414 
415 /**
416  * Returns the number of child classes that the indicated type is known to
417  * have. This may then be used to index into get_child_class().
418  *
419  * The "object" pointer is an optional pointer to the TypedObject class that
420  * owns this TypeHandle. It is only used in case the TypeHandle is
421  * inadvertantly undefined.
422  */
423 int TypeRegistry::
424 get_num_child_classes(TypeHandle child, TypedObject *child_object) const {
425  _lock->lock();
426  TypeRegistryNode *rnode = look_up(child, child_object);
427  assert(rnode != nullptr);
428  int num_children = (int)rnode->_child_classes.size();
429  _lock->unlock();
430  return num_children;
431 }
432 
433 /**
434  * Returns the nth child class of this type. The index should be in the range
435  * 0 <= index < get_num_child_classes().
436  */
438 get_child_class(TypeHandle child, int index) const {
439  _lock->lock();
440  TypeHandle handle;
441  TypeRegistryNode *rnode = look_up(child, nullptr);
442  assert(rnode != nullptr);
443  if (index >= 0 && index < (int)rnode->_child_classes.size()) {
444  handle = rnode->_child_classes[index]->_handle;
445  } else {
446  handle = TypeHandle::none();
447  }
448  _lock->unlock();
449  return handle;
450 }
451 
452 /**
453  * Returns the parent of the indicated child class that is in a direct line of
454  * inheritance to the indicated ancestor class. This is useful in the
455  * presence of multiple inheritance to try to determine what properties an
456  * unknown type may have.
457  *
458  * The "object" pointer is an optional pointer to the TypedObject class that
459  * owns this TypeHandle. It is only used in case the TypeHandle is
460  * inadvertantly undefined.
461  */
464  TypedObject *child_object) {
465  _lock->lock();
466  TypeHandle handle;
467  const TypeRegistryNode *child_node = look_up(child, child_object);
468  const TypeRegistryNode *base_node = look_up(base, nullptr);
469  assert(child_node != nullptr &&
470  base_node != nullptr);
471  freshen_derivations();
472  handle = TypeRegistryNode::get_parent_towards(child_node, base_node);
473  _lock->unlock();
474  return handle;
475 }
476 
477 
478 /**
479  * Walks through the TypeRegistry tree and makes sure that each type that was
480  * previously registered is *still* registered. This seems to get broken in
481  * certain circumstances when compiled against libc5--it is as if the static
482  * initializer stomps on the _type_handle values of each class after they've
483  * been registered.
484  */
485 void TypeRegistry::
487  init_lock();
488  _lock->lock();
489  HandleRegistry::iterator ri;
490  TypeRegistry *reg = ptr();
491  for (ri = reg->_handle_registry.begin();
492  ri != reg->_handle_registry.end();
493  ++ri) {
494  TypeRegistryNode *rnode = (*ri);
495  if (rnode != nullptr && rnode->_handle != rnode->_ref) {
496  cerr << "Reregistering " << rnode->_name << "\n";
497  }
498  }
499  _lock->unlock();
500 }
501 
502 
503 /**
504  * Makes an attempt to format the entire TypeRegistry in a nice way that shows
505  * the derivation tree as intelligently as possible.
506  */
507 void TypeRegistry::
508 write(ostream &out) const {
509  _lock->lock();
510  do_write(out);
511  _lock->unlock();
512 }
513 
514 /**
515  *
516  */
517 TypeRegistry::
518 TypeRegistry() {
519  // We'll start out our handle_registry with a default entry for the
520  // TypeHandles whose index number is zero, and are therefore (probably)
521  // uninitialized.
522  _handle_registry.push_back(nullptr);
523 
524  _derivations_fresh = false;
525 
526  // Here's a few sanity checks on the sizes of our words. We have to put it
527  // here, at runtime, since there doesn't appear to be a cross-platform
528  // compile-time way to verify that we've chosen the right word sizes.
529  assert(sizeof(uint8_t) == 1 && sizeof(int8_t) == 1);
530  assert(sizeof(uint16_t) == 2 && sizeof(int16_t) == 2);
531  assert(sizeof(uint32_t) == 4 && sizeof(int32_t) == 4);
532  assert(sizeof(uint64_t) == 8 && sizeof(int64_t) == 8);
533 
534  assert(sizeof(PN_float32) == 4);
535  assert(sizeof(PN_float64) == 8);
536 }
537 
538 /**
539  * Constructs the TypeRegistry object for the first time.
540  */
541 void TypeRegistry::
542 init_global_pointer() {
543  init_lock();
545  _global_pointer = new TypeRegistry;
546 }
547 
548 /**
549  * Rebuilds the derivation data structures after some derivation relationship
550  * has been modified, so that class relationships can quickly be determined.
551  */
552 void TypeRegistry::
553 rebuild_derivations() {
554  // First, remove all of the old data from the last type
555  // rebuild_derivations() was called.
556  _root_classes.clear();
557 
558  HandleRegistry::iterator hi;
559  for (hi = _handle_registry.begin();
560  hi != _handle_registry.end();
561  ++hi) {
562  TypeRegistryNode *node = *hi;
563  if (node != nullptr) {
564  node->clear_subtree();
565  }
566  }
567 
568  // Start by getting the list of root classes: those classes which do not
569  // derive from anything.
570  for (hi = _handle_registry.begin();
571  hi != _handle_registry.end();
572  ++hi) {
573  TypeRegistryNode *node = *hi;
574  if (node != nullptr && node->_parent_classes.empty()) {
575  _root_classes.push_back(node);
576 
577  // Also, for each root class, define a subtree.
578  node->define_subtree();
579  }
580  }
581 }
582 
583 /**
584  * The private implementation of write(), this assumes the lock is already
585  * held.
586  */
587 void TypeRegistry::
588 do_write(ostream &out) const {
589  // Recursively write out the tree, starting from each node that has no
590  // parent.
591  HandleRegistry::const_iterator hi;
592  for (hi = _handle_registry.begin();
593  hi != _handle_registry.end();
594  ++hi) {
595  const TypeRegistryNode *root = *hi;
596  if (root != nullptr && root->_parent_classes.empty()) {
597  write_node(out, 2, root);
598  }
599  }
600 }
601 
602 /**
603  * Writes a single TypeRegistryNode out, along with all of its descendants.
604  * Assumes the lock is already held.
605  */
606 void TypeRegistry::
607 write_node(ostream &out, int indent_level, const TypeRegistryNode *node) const {
608  indent(out, indent_level) << node->_handle.get_index() << " " << node->_name;
609  if (!node->_parent_classes.empty()) {
610  out << " : " << node->_parent_classes[0]->_name;
611  for (int pi = 1; pi < (int)node->_parent_classes.size(); pi++) {
612  out << ", " << node->_parent_classes[pi]->_name;
613  }
614  }
615  out << "\n";
616 
617  for (int i = 0; i < (int)node->_child_classes.size(); i++) {
618  write_node(out, indent_level + 2, node->_child_classes[i]);
619  }
620 }
621 
622 /**
623  * Called by look_up when it detects an invalid TypeHandle pointer. In non-
624  * release builds, this method will do what it can to recover from this and
625  * initialize the type anyway.
626  *
627  * Assumes the lock is already held.
628  */
629 TypeRegistryNode *TypeRegistry::
630 look_up_invalid(TypeHandle handle, TypedObject *object) const {
631 #ifndef NDEBUG
632  if (handle._index == 0) {
633  // The TypeHandle is unregistered. This is an error condition.
634 
635  if (object != nullptr) {
636  // But we're lucky enough to have a TypedObject pointer handy! Maybe we
637  // can use it to resolve the error. We have to drop the lock while we
638  // do this, so we don't get a recursive lock.
639  _lock->unlock();
640  handle = object->force_init_type();
641  _lock->lock();
642 
643  if (handle._index == 0) {
644  // Strange.
645  cerr
646  << "Unable to force_init_type() on unregistered TypeHandle.\n";
647  return nullptr;
648  }
649 
650  // Now get the name for printing. We can't use TypeHandle:: get_name()
651  // since that recursively calls look_up().
652  ostringstream name;
653  if (handle._index > 0 && handle._index < (int)_handle_registry.size()) {
654  TypeRegistryNode *rnode = _handle_registry[handle._index];
655  if (rnode != nullptr) {
656  name << rnode->_name;
657  name << " (index " << handle._index << ")";
658  } else {
659  name << "NULL (index " << handle._index << ")";
660  }
661  } else {
662  name << "index " << handle._index;
663  }
664 
665  if (handle == object->get_type()) {
666  // Problem solved!
667  cerr
668  << "Type " << name.str() << " was unregistered!\n";
669  } else {
670  // No good; it looks like the TypeHandle belongs to a class that
671  // defined get_type(), but didn't define force_init_type().
672  cerr
673  << "Attempt to reference unregistered TypeHandle. Type is of some\n"
674  << "class derived from type " << name.str() << " that doesn't define\n"
675  << "a good force_init_type() method.\n";
676  return nullptr;
677  }
678 
679  } else {
680  // We don't have a TypedObject pointer, so there's nothing we can do
681  // about it.
682  cerr
683  << "Attempt to reference unregistered TypeHandle!\n"
684  << "Registered TypeHandles are:\n";
685  do_write(cerr);
686  return nullptr;
687  }
688  }
689 
690  if (handle._index < 0 ||
691  handle._index >= (int)_handle_registry.size()) {
692  cerr
693  << "Invalid TypeHandle index " << handle._index
694  << "! Is memory corrupt?\n";
695  return nullptr;
696  }
697 #endif // NDEBUG
698 
699  return _handle_registry[handle._index];
700 }
701 
702 /**
703 
704  */
705 extern "C" int
706 get_best_parent_from_Set(int id, const std::set<int> &this_set) {
707  // most common case..
708  if (this_set.find(id) != this_set.end()) {
709  return id;
710  }
711 
713  if (th == TypeHandle::none()) {
714  return -1;
715  }
716 
717  return th.get_best_parent_from_Set(this_set);
718 }
bool is_derived_from(TypeHandle child, TypeHandle base, TypedObject *child_object)
Returns true if the first type is derived from the second type, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_best_parent_from_Set(const std::set< int > &legal_vals) const
Return the Index of the BEst fit Classs from a set.
Definition: typeHandle.cxx:175
void clear_subtree()
Removes any subtree definition previously set up via define_subtree(), in preparation for rebuilding ...
TypeHandle find_type_by_id(int id) const
Looks for a previously-registered type with the given id number (as returned by TypeHandle::get_index...
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.
get_root_class
Returns the nth root class in the system.
Definition: typeRegistry.h:65
std::string get_name(TypeHandle type, TypedObject *object) const
Returns the name of the indicated type.
void record_alternate_name(TypeHandle type, const std::string &name)
Indicates an alternate name for the same type.
void init_memory_hook()
Any code that might need to use PANDA_MALLOC or PANDA_FREE, or any methods of the global memory_hook ...
Definition: dtoolbase.cxx:38
int get_num_child_classes(TypeHandle child, TypedObject *child_object) const
Returns the number of child classes that the indicated type is known to have.
This is an abstract class that all classes which use TypeHandle, and also provide virtual functions t...
Definition: typedObject.h:88
TypeHandle register_dynamic_type(const std::string &name)
Registers a new type on-the-fly, presumably at runtime.
TypeHandle find_type(const std::string &name) const
Looks for a previously-registered type of the given name.
This is a single entry in the TypeRegistry.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle get_parent_class(TypeHandle child, int index) const
Returns the nth parent class of this type.
TypeHandle get_parent_towards(TypeHandle child, TypeHandle base, TypedObject *child_object)
Returns the parent of the indicated child class that is in a direct line of inheritance to the indica...
bool register_type(TypeHandle &type_handle, const std::string &name)
Creates a new Type of the given name and assigns a unique value to the type_handle.
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...
int get_num_parent_classes(TypeHandle child, TypedObject *child_object) const
Returns the number of parent classes that the indicated type is known to have.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
get_index
Returns the integer index associated with this TypeHandle.
Definition: typeHandle.h:135
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle get_child_class(TypeHandle child, int index) const
Returns the nth child class of this type.
static void reregister_types()
Walks through the TypeRegistry tree and makes sure that each type that was previously registered is *...
get_typehandle
Returns the nth TypeHandle in the system.
Definition: typeRegistry.h:61
static TypeRegistry * ptr()
Returns the pointer to the global TypeRegistry object.
Definition: typeRegistry.I:30
The TypeRegistry class maintains all the assigned TypeHandles in a given system.
Definition: typeRegistry.h:36
void define_subtree()
Indicates that this TypeRegistryNode is the top of a subtree within the inheritance graph (typically,...
A fake mutex implementation for single-threaded applications that don't need any synchronization cont...
void write(std::ostream &out) const
Makes an attempt to format the entire TypeRegistry in a nice way that shows the derivation tree as in...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void record_derivation(TypeHandle child, TypeHandle parent)
Records that the type referenced by child inherits directly from the type referenced by parent.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.