Browse Source

optimize is_of_type(), in theory

David Rose 24 years ago
parent
commit
764aea593e
36 changed files with 2235 additions and 1434 deletions
  1. 1 0
      panda/src/dgraph/buttonEventDataTransition.cxx
  2. 2 1
      panda/src/egg/eggBinMaker.cxx
  3. 3 1
      panda/src/egg/eggPolysetMaker.h
  4. 6 6
      panda/src/egg/parser.yxx
  5. 24 4
      panda/src/express/Sources.pp
  6. 127 0
      panda/src/express/dcast.T
  7. 90 0
      panda/src/express/dcast.h
  8. 3 0
      panda/src/express/express_composite2.cxx
  9. 120 0
      panda/src/express/register_type.I
  10. 61 0
      panda/src/express/register_type.cxx
  11. 285 0
      panda/src/express/register_type.h
  12. 1 0
      panda/src/express/test_types.cxx
  13. 0 217
      panda/src/express/typeHandle.I
  14. 0 681
      panda/src/express/typeHandle.cxx
  15. 8 353
      panda/src/express/typeHandle.h
  16. 79 0
      panda/src/express/typeRegistry.I
  17. 608 0
      panda/src/express/typeRegistry.cxx
  18. 116 0
      panda/src/express/typeRegistry.h
  19. 104 0
      panda/src/express/typeRegistryNode.I
  20. 377 0
      panda/src/express/typeRegistryNode.cxx
  21. 101 0
      panda/src/express/typeRegistryNode.h
  22. 2 58
      panda/src/express/typedObject.h
  23. 48 47
      panda/src/glgsg/glGraphicsStateGuardian.cxx
  24. 3 2
      panda/src/graph/nodeTransition.h
  25. 3 2
      panda/src/graph/nodeTransitions.h
  26. 3 3
      panda/src/graph/nullLevelState.h
  27. 20 20
      panda/src/graph/nullTransitionWrapper.I
  28. 26 22
      panda/src/graph/nullTransitionWrapper.h
  29. 1 0
      panda/src/mathutil/boundingSphere.cxx
  30. 3 2
      panda/src/pnmimage/pnmFileTypeRegistry.cxx
  31. 0 10
      panda/src/putil/Sources.pp
  32. 2 0
      panda/src/putil/bamReader.h
  33. 1 0
      panda/src/sgattrib/alphaTransformTransition.cxx
  34. 2 1
      panda/src/sgattrib/fogTransition.cxx
  35. 2 2
      panda/src/sgraphutil/quickRenderTraverser.cxx
  36. 3 2
      panda/src/vrpn/vrpnClient.cxx

+ 1 - 0
panda/src/dgraph/buttonEventDataTransition.cxx

@@ -22,6 +22,7 @@
 
 #include "indent.h"
 #include "modifierButtons.h"
+#include "dcast.h"
 
 #include <algorithm>
 

+ 2 - 1
panda/src/egg/eggBinMaker.cxx

@@ -21,7 +21,8 @@
 #include "eggGroup.h"
 #include "eggBin.h"
 
-#include <notify.h>
+#include "dcast.h"
+#include "notify.h"
 
 TypeHandle EggBinMaker::_type_handle;
 

+ 3 - 1
panda/src/egg/eggPolysetMaker.h

@@ -19,10 +19,12 @@
 #ifndef EGGPOLYSETMAKER_H
 #define EGGPOLYSETMAKER_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "eggBinMaker.h"
 
+#include "dcast.h"
+
 ///////////////////////////////////////////////////////////////////
 //       Class : EggPolysetMaker
 // Description : A specialization on EggBinMaker for making polysets

+ 6 - 6
panda/src/egg/parser.yxx

@@ -29,13 +29,13 @@
 #include "pt_EggTexture.h"
 #include "pt_EggMaterial.h"
 
-#include <string_utils.h>
-#include <filename.h>
-#include <luse.h>
-#include <lmatrix.h>
-#include <coordinateSystem.h>
-
+#include "string_utils.h"
+#include "filename.h"
+#include "luse.h"
+#include "lmatrix.h"
+#include "coordinateSystem.h"
 #include "pvector.h"
+#include "dcast.h"
 
 // Because our token type contains objects of type string, which
 // require correct copy construction (and not simply memcpying), we

+ 24 - 4
panda/src/express/Sources.pp

@@ -18,6 +18,7 @@
      datagramGenerator.h datagramInputFile.I datagramInputFile.h \
      datagramIterator.I datagramIterator.h datagramOutputFile.I \
      datagramOutputFile.h datagramSink.I datagramSink.h \
+     dcast.T dcast.h \
      error_utils.h \
      get_config_path.h hashGeneratorBase.I hashGeneratorBase.h \
      hashVal.I hashVal.h indent.I indent.h littleEndian.h \
@@ -31,10 +32,13 @@
      pointerToArray.I pointerToArray.h \
      profileTimer.I profileTimer.h \
      pta_uchar.h referenceCount.I referenceCount.h \
+     register_type.I register_type.h \
      reversedNumericData.I reversedNumericData.h tokenBoard.I \
      tokenBoard.h trueClock.I trueClock.h typeHandle.I \
      typeHandle.h typedObject.I typedObject.h \
      typedReferenceCount.I typedReferenceCount.h typedef.h \
+     typeRegistry.I typeRegistry.h \
+     typeRegistryNode.I typeRegistryNode.h \
      vector_uchar.h
     
   #define INCLUDED_SOURCES  \
@@ -47,10 +51,10 @@
      memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
      memoryUsagePointers.cxx multifile.cxx namable.cxx \
      nativeNumericData.cxx profileTimer.cxx \
-     pta_uchar.cxx referenceCount.cxx \
+     pta_uchar.cxx referenceCount.cxx register_type.cxx \
      reversedNumericData.cxx trueClock.cxx typeHandle.cxx \
      typedObject.cxx typedReferenceCount.cxx \
-     vector_uchar.cxx
+     typeRegistry.cxx typeRegistryNode.cxx vector_uchar.cxx
 
   #define IF_CRYPTO_SOURCES                         \
     crypto_utils.cxx crypto_utils.h \
@@ -63,7 +67,8 @@
     datagramGenerator.I datagramGenerator.h datagramInputFile.I \
     datagramInputFile.h datagramIterator.I datagramIterator.h \
     datagramOutputFile.I datagramOutputFile.h datagramSink.I \
-    datagramSink.h error_utils.h get_config_path.h hashGeneratorBase.I \
+    datagramSink.h dcast.T dcast.h \
+    error_utils.h get_config_path.h hashGeneratorBase.I \
     hashGeneratorBase.h hashVal.I hashVal.h indent.I indent.h \
     littleEndian.h memoryInfo.I memoryInfo.h memoryUsage.I \
     memoryUsage.h memoryUsagePointerCounts.I \
@@ -73,11 +78,26 @@
     patchfile.I patchfile.h pointerTo.I pointerTo.h \
     pointerToArray.I pointerToArray.h profileTimer.I \
     profileTimer.h pta_uchar.h referenceCount.I referenceCount.h \
+    register_type.I register_type.h \
     reversedNumericData.I reversedNumericData.h tokenBoard.I \
     tokenBoard.h trueClock.I trueClock.h typeHandle.I typeHandle.h \
     typedObject.I typedObject.h typedReferenceCount.I \
-    typedReferenceCount.h typedef.h vector_uchar.h
+    typedReferenceCount.h typedef.h \
+    typeRegistry.I typeRegistry.h \
+    typeRegistryNode.I typeRegistryNode.h \
+    vector_uchar.h
 
   #define IGATESCAN all
 
 #end lib_target
+
+#begin test_bin_target
+  #define TARGET test_types
+  #define LOCAL_LIBS $[LOCAL_LIBS] express
+  #define OTHER_LIBS pystub
+
+  #define SOURCES \
+    test_types.cxx
+
+#end test_bin_target
+

+ 127 - 0
panda/src/express/dcast.T

@@ -0,0 +1,127 @@
+// Filename: dcast.T
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: _dcast_get_typehandle
+//  Description: Returns the TypeHandle associated with the type of
+//               the parameter, if it can be determined.  This is a
+//               support function for _dcast, below.
+////////////////////////////////////////////////////////////////////
+template<class WantType>
+INLINE TypeHandle
+_dcast_get_typehandle(WantType *) {
+  TypeHandle handle = WantType::get_class_type();
+  if (handle == TypeHandle::none()) {
+    // This type handle is unregistered.  Oops!
+    WantType::init_type();
+    handle = WantType::get_class_type();
+    express_cat->warning()
+      << "Type " << handle << " was unregistered!\n";
+  }
+  return handle;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: _dcast
+//  Description: The implementation of the DCAST macro, this checks
+//               the actual type of the pointer before performing a
+//               downcast operation.  In NDEBUG mode, it simply
+//               downcasts.
+//
+//               This flavor of _dcast works on non-const pointers.
+////////////////////////////////////////////////////////////////////
+template<class WantType>
+INLINE WantType *
+_dcast(WantType *, TypedObject *ptr) {
+#ifndef NDEBUG
+  TypeHandle want_handle = _dcast_get_typehandle((WantType *)0);
+ #if defined(_DEBUG) && defined(_WIN32)
+  if ((ptr == (TypedObject *)NULL) || IsBadWritePtr(ptr,sizeof(TypedObject))) {
+ #else
+  if (ptr == (TypedObject *)NULL) {
+ #endif
+    express_cat->warning()
+      << "Attempt to cast NULL pointer to " << want_handle << "\n";
+    return (WantType *)NULL;
+  }
+  if (!ptr->is_of_type(want_handle)) {
+    express_cat->error()
+      << "Attempt to cast pointer from " << ptr->get_type()
+      << " to " << want_handle << "\n";
+    if (ptr->get_type() == TypedObject::get_class_type()) {
+      express_cat->error(false)
+        << "Perhaps pointer was inadvertently deleted?\n";
+    }
+    return (WantType *)NULL;
+  }
+#endif
+  return (WantType *)ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: _dcast
+//  Description: The implementation of the DCAST macro, this checks
+//               the actual type of the pointer before performing a
+//               downcast operation.  In NDEBUG mode, it simply
+//               downcasts.
+//
+//               This flavor of _dcast works on const pointers.
+////////////////////////////////////////////////////////////////////
+template<class WantType>
+INLINE const WantType *
+_dcast(WantType *, const TypedObject *ptr) {
+#ifndef NDEBUG
+  TypeHandle want_handle = _dcast_get_typehandle((WantType *)0);
+  if (ptr == (const TypedObject *)NULL) {
+    express_cat->warning()
+      << "Attempt to cast NULL pointer to " << want_handle << "\n";
+    return (const WantType *)NULL;
+  }
+  if (!ptr->is_of_type(want_handle)) {
+    express_cat->error()
+      << "Attempt to cast pointer from " << ptr->get_type()
+      << " to " << want_handle << "\n";
+    if (ptr->get_type() == TypedObject::get_class_type()) {
+      express_cat->error(false)
+        << "Perhaps pointer was inadvertently deleted?\n";
+    }
+    return (const WantType *)NULL;
+  }
+#endif
+  return (const WantType *)ptr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: _dcast_ref
+//  Description: Similar to the above, with a pointer reference as the
+//               first parameter.  Just for fiddly compiler reasons;
+//               the reference isn't used.
+////////////////////////////////////////////////////////////////////
+template<class WantType>
+INLINE WantType *
+_dcast_ref(WantType *&, TypedObject *ptr) {
+  return _dcast((WantType *)NULL, ptr);
+}
+
+template<class WantType>
+INLINE const WantType *
+_dcast_ref(WantType *&, const TypedObject *ptr) {
+  return _dcast((WantType *)NULL, ptr);
+}

+ 90 - 0
panda/src/express/dcast.h

@@ -0,0 +1,90 @@
+// Filename: dcast.h
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef DCAST_H
+#define DCAST_H
+
+#include "pandabase.h"
+
+#include "typeHandle.h"
+#include "typedObject.h"
+
+#if defined(_DEBUG) && defined(_WIN32)
+#include <windows.h>  // for IsBadWritePtr()
+#endif
+
+// The DCAST (downcast) macro is defined as a convenience for
+// downcasting from some TypedObject pointer (or a PointerTo).  It's
+// just a normal C++-style downcast, except it first checks get_type()
+// to make sure the downcasting is safe.  If you compile with NDEBUG,
+// this check is removed.
+
+// DCAST will return NULL if the downcasting is unsafe.  If you'd
+// rather it abort out of the function (ala nassertv/nassertr), then
+// see DCAST_INTO_V and DCAST_INTO_R, below.
+
+template<class WantType>
+INLINE WantType *_dcast(WantType *, TypedObject *ptr);
+template<class WantType>
+INLINE const WantType *_dcast(WantType *, const TypedObject *ptr);
+
+// Note: it is important that DCAST not repeat the pointer parameter,
+// since many users of DCAST may want to use the result of a function
+// as the pointer parameter, and it could be terribly confusing and
+// difficult to trace if the function were inadvertently executed
+// twice.  This happened!
+#define DCAST(want_type, pointer) _dcast((want_type*)0, pointer)
+
+// DCAST_INTO_V and DCAST_INTO_R are similar in purpose to DCAST,
+// except they: (a) automatically assign a variable instead of
+// returning the downcasted pointer, and (b) they immediately return
+// out of the function if the downcasting fails.  DCAST_INTO_V is for
+// use in a void function and returns nothing; DCAST_INTO_R is for use
+// in a non-void function and returns the indicated value.
+
+// Both DCAST_INTO_V and DCAST_INTO_R accept as the first parameter a
+// variable of type (want_type *) or (const want_type *), instead of
+// the name of the type.  This variable will be filled with the new
+// pointer.
+
+
+// _dcast_ref is used to implement DCAST_INTO_V and DCAST_INTO_R.  Its
+// difference from _dcast is that it takes a reference to a pointer as
+// a first parameter.  The main point of this is to shut up the
+// compiler about pointers used before their value is assigned.
+template<class WantType>
+INLINE WantType *_dcast_ref(WantType *&, TypedObject *ptr);
+template<class WantType>
+INLINE const WantType *_dcast_ref(WantType *&, const TypedObject *ptr);
+
+
+#define DCAST_INTO_V(to_pointer, from_pointer) \
+  { \
+    (to_pointer) = _dcast_ref(to_pointer, from_pointer); \
+    nassertv((void *)(to_pointer) != (void *)NULL); \
+  }
+
+#define DCAST_INTO_R(to_pointer, from_pointer, return_value) \
+  { \
+    (to_pointer) = _dcast_ref(to_pointer, from_pointer); \
+    nassertr((void *)(to_pointer) != (void *)NULL, return_value); \
+  }
+
+#include "dcast.T"
+
+#endif

+ 3 - 0
panda/src/express/express_composite2.cxx

@@ -5,10 +5,13 @@
 #include "profileTimer.cxx"
 #include "pta_uchar.cxx"
 #include "referenceCount.cxx"
+#include "register_type.cxx"
 #include "reversedNumericData.cxx"
 #include "trueClock.cxx"
 #include "typeHandle.cxx"
 #include "typedObject.cxx"
 #include "typedReferenceCount.cxx"
+#include "typeRegistry.cxx"
+#include "typeRegistryNode.cxx"
 #include "vector_uchar.cxx"
 

+ 120 - 0
panda/src/express/register_type.I

@@ -0,0 +1,120 @@
+// Filename: register_type.I
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: register_type
+//  Description: This inline function is just a convenient way to call
+//               TypeRegistry::register_type(), along with zero to four
+//               record_derivation()s.  If for some reason you have a
+//               class that has more than four base classes (you're
+//               insane!), then you will need to call Register() and
+//               record_derivation() yourself.
+////////////////////////////////////////////////////////////////////
+INLINE void
+register_type(TypeHandle &type_handle, const string &name) {
+  TypeRegistry::ptr()->register_type(type_handle, name);
+}
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1) {
+  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
+    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+  }
+}
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1, TypeHandle parent2) {
+  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
+    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+    TypeRegistry::ptr()->record_derivation(type_handle, parent2);
+  }
+}
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1, TypeHandle parent2,
+              TypeHandle parent3) {
+  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
+    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+    TypeRegistry::ptr()->record_derivation(type_handle, parent2);
+    TypeRegistry::ptr()->record_derivation(type_handle, parent3);
+  }
+}
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1, TypeHandle parent2,
+              TypeHandle parent3, TypeHandle parent4) {
+  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
+    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+    TypeRegistry::ptr()->record_derivation(type_handle, parent2);
+    TypeRegistry::ptr()->record_derivation(type_handle, parent3);
+    TypeRegistry::ptr()->record_derivation(type_handle, parent4);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: register_dynamic_type
+//  Description: This is essentially similar to register_type(),
+//               except that it doesn't store a reference to any
+//               TypeHandle passed in and it therefore doesn't
+//               complain if the type is registered more than once to
+//               different TypeHandle reference.
+////////////////////////////////////////////////////////////////////
+INLINE TypeHandle
+register_dynamic_type(const string &name) {
+  return TypeRegistry::ptr()->register_dynamic_type(name);
+}
+INLINE TypeHandle
+register_dynamic_type(const string &name, TypeHandle parent1) {
+  TypeHandle type_handle =
+    TypeRegistry::ptr()->register_dynamic_type(name);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+  return type_handle;
+}
+INLINE TypeHandle
+register_dynamic_type(const string &name,
+                      TypeHandle parent1, TypeHandle parent2) {
+  TypeHandle type_handle =
+    TypeRegistry::ptr()->register_dynamic_type(name);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent2);
+  return type_handle;
+}
+INLINE TypeHandle
+register_dynamic_type(const string &name,
+                      TypeHandle parent1, TypeHandle parent2,
+                      TypeHandle parent3) {
+  TypeHandle type_handle =
+    TypeRegistry::ptr()->register_dynamic_type(name);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent2);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent3);
+  return type_handle;
+}
+INLINE TypeHandle
+register_dynamic_type(const string &name,
+                      TypeHandle parent1, TypeHandle parent2,
+                      TypeHandle parent3, TypeHandle parent4) {
+  TypeHandle type_handle =
+    TypeRegistry::ptr()->register_dynamic_type(name);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent2);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent3);
+  TypeRegistry::ptr()->record_derivation(type_handle, parent4);
+  return type_handle;
+}

+ 61 - 0
panda/src/express/register_type.cxx

@@ -0,0 +1,61 @@
+// Filename: register_type.cxx
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "register_type.h"
+
+
+TypeHandle long_type_handle;
+TypeHandle int_type_handle;
+TypeHandle short_type_handle;
+TypeHandle char_type_handle;
+TypeHandle bool_type_handle;
+TypeHandle double_type_handle;
+TypeHandle float_type_handle;
+
+TypeHandle long_p_type_handle;
+TypeHandle int_p_type_handle;
+TypeHandle short_p_type_handle;
+TypeHandle char_p_type_handle;
+TypeHandle bool_p_type_handle;
+TypeHandle double_p_type_handle;
+TypeHandle float_p_type_handle;
+TypeHandle void_p_type_handle;
+
+void init_system_type_handles() {
+  static bool done = false;
+  if (!done) {
+    done = true;
+    register_type(long_type_handle, "long");
+    register_type(int_type_handle, "int");
+    register_type(short_type_handle, "short");
+    register_type(char_type_handle, "char");
+    register_type(bool_type_handle, "bool");
+    register_type(double_type_handle, "double");
+    register_type(float_type_handle, "float");
+
+    register_type(int_p_type_handle, "int*");
+    register_type(short_p_type_handle, "short*");
+    register_type(char_p_type_handle, "char*");
+    register_type(bool_p_type_handle, "bool*");
+    register_type(double_p_type_handle, "double*");
+    register_type(float_p_type_handle, "float*");
+    register_type(void_p_type_handle, "void*");
+  }
+}
+
+

+ 285 - 0
panda/src/express/register_type.h

@@ -0,0 +1,285 @@
+// Filename: register_type.h
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef REGISTER_TYPE_H
+#define REGISTER_TYPE_H
+
+#include "pandabase.h"
+
+#include "typeHandle.h"
+#include "typeRegistry.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: register_type
+//  Description: This inline function is just a convenient way to call
+//               TypeRegistry::register_type(), along with zero to four
+//               record_derivation()s.  If for some reason you have a
+//               class that has more than four base classes (you're
+//               insane!), then you will need to call Register() and
+//               record_derivation() yourself.
+////////////////////////////////////////////////////////////////////
+INLINE void
+register_type(TypeHandle &type_handle, const string &name);
+
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1);
+
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1, TypeHandle parent2);
+
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1, TypeHandle parent2,
+              TypeHandle parent3);
+
+INLINE void
+register_type(TypeHandle &type_handle, const string &name,
+              TypeHandle parent1, TypeHandle parent2,
+              TypeHandle parent3, TypeHandle parent4);
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: register_dynamic_type
+//  Description: This is essentially similar to register_type(),
+//               except that it doesn't store a reference to any
+//               TypeHandle passed in and it therefore doesn't
+//               complain if the type is registered more than once to
+//               different TypeHandle reference.
+////////////////////////////////////////////////////////////////////
+INLINE TypeHandle
+register_dynamic_type(const string &name);
+
+INLINE TypeHandle
+register_dynamic_type(const string &name, TypeHandle parent1);
+
+INLINE TypeHandle
+register_dynamic_type(const string &name,
+                      TypeHandle parent1, TypeHandle parent2);
+
+INLINE TypeHandle
+register_dynamic_type(const string &name,
+                      TypeHandle parent1, TypeHandle parent2,
+                      TypeHandle parent3);
+
+INLINE TypeHandle
+register_dynamic_type(const string &name,
+                      TypeHandle parent1, TypeHandle parent2,
+                      TypeHandle parent3, TypeHandle parent4);
+
+
+// A few system-wide TypeHandles are defined for some basic types.
+extern TypeHandle EXPCL_PANDAEXPRESS long_type_handle;
+extern TypeHandle EXPCL_PANDAEXPRESS int_type_handle;
+extern TypeHandle EXPCL_PANDAEXPRESS short_type_handle;
+extern TypeHandle EXPCL_PANDAEXPRESS char_type_handle;
+extern TypeHandle EXPCL_PANDAEXPRESS bool_type_handle;
+extern TypeHandle EXPCL_PANDAEXPRESS double_type_handle;
+extern TypeHandle EXPCL_PANDAEXPRESS float_type_handle;
+
+extern TypeHandle long_p_type_handle;
+extern TypeHandle int_p_type_handle;
+extern TypeHandle short_p_type_handle;
+extern TypeHandle char_p_type_handle;
+extern TypeHandle bool_p_type_handle;
+extern TypeHandle double_p_type_handle;
+extern TypeHandle float_p_type_handle;
+extern TypeHandle void_p_type_handle;
+
+void EXPCL_PANDAEXPRESS init_system_type_handles();
+
+// The following template function and its specializations will return
+// a TypeHandle for any type in the world, from a pointer to that
+// type.
+
+template<class T>
+INLINE TypeHandle _get_type_handle(const T *) {
+  return T::get_class_type();
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const long *) {
+  return long_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const int *) {
+  return int_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const short *) {
+  return short_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const char *) {
+  return char_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const bool *) {
+  return bool_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const double *) {
+  return double_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const float *) {
+  return float_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const long * const *) {
+  return long_p_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const int * const *) {
+  return int_p_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const short * const *) {
+  return short_p_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const char * const *) {
+  return char_p_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const bool * const *) {
+  return bool_p_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const double * const *) {
+  return double_p_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const float * const *) {
+  return float_p_type_handle;
+}
+
+template<>
+INLINE TypeHandle _get_type_handle(const void * const *) {
+  return void_p_type_handle;
+}
+
+
+// The macro get_type_handle(type) is defined to make getting the type
+// handle associated with a particular type a bit cleaner.
+#define get_type_handle(type) _get_type_handle((const type *)0)
+
+
+// The following template function and its specializations can be used
+// to call init() on any unknown type.  Handy for use within a
+// template class.
+
+template<class T>
+INLINE void _do_init_type(const T *) {
+  T::init_type();
+}
+
+template<>
+INLINE void _do_init_type(const long *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const int *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const short *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const char *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const bool *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const double *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const float *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const long * const *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const int * const *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const short * const *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const char * const *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const bool * const *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const double * const *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const float * const *) {
+  init_system_type_handles();
+}
+
+template<>
+INLINE void _do_init_type(const void * const *) {
+  init_system_type_handles();
+}
+
+#define do_init_type(type) _do_init_type((const type *)0)
+
+#include "register_type.I"
+
+#endif

+ 1 - 0
panda/src/putil/test_types.cxx → panda/src/express/test_types.cxx

@@ -38,6 +38,7 @@ public:
     TypedObject::init_type();
     ReferenceCount::init_type();
     register_type(_type_handle, "ThatThingie",
+                  TypedObject::get_class_type(),
                   ReferenceCount::get_class_type());
   }
   virtual TypeHandle get_type() const {

+ 0 - 217
panda/src/express/typeHandle.I

@@ -16,11 +16,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "config_express.h"
-
-#if defined(_DEBUG) && defined(_WIN32)
-#include <windows.h>
-#endif
 
 // In general, we use the express_cat->info() syntax in this file
 // (instead of express_cat.info()), because much of this work is done at
@@ -226,215 +221,3 @@ none() {
   return _none;
 }
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: register_type
-//  Description: This inline function is just a convenient way to call
-//               TypeRegistry::register_type(), along with zero to four
-//               record_derivation()s.  If for some reason you have a
-//               class that has more than four base classes (you're
-//               insane!), then you will need to call Register() and
-//               record_derivation() yourself.
-////////////////////////////////////////////////////////////////////
-INLINE void
-register_type(TypeHandle &type_handle, const string &name) {
-  TypeRegistry::ptr()->register_type(type_handle, name);
-}
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1) {
-  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
-    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-  }
-}
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1, TypeHandle parent2) {
-  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
-    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-    TypeRegistry::ptr()->record_derivation(type_handle, parent2);
-  }
-}
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1, TypeHandle parent2,
-              TypeHandle parent3) {
-  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
-    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-    TypeRegistry::ptr()->record_derivation(type_handle, parent2);
-    TypeRegistry::ptr()->record_derivation(type_handle, parent3);
-  }
-}
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1, TypeHandle parent2,
-              TypeHandle parent3, TypeHandle parent4) {
-  if (TypeRegistry::ptr()->register_type(type_handle, name)) {
-    TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-    TypeRegistry::ptr()->record_derivation(type_handle, parent2);
-    TypeRegistry::ptr()->record_derivation(type_handle, parent3);
-    TypeRegistry::ptr()->record_derivation(type_handle, parent4);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: register_dynamic_type
-//  Description: This is essentially similar to register_type(),
-//               except that it doesn't store a reference to any
-//               TypeHandle passed in and it therefore doesn't
-//               complain if the type is registered more than once to
-//               different TypeHandle reference.
-////////////////////////////////////////////////////////////////////
-INLINE TypeHandle
-register_dynamic_type(const string &name) {
-  return TypeRegistry::ptr()->register_dynamic_type(name);
-}
-INLINE TypeHandle
-register_dynamic_type(const string &name, TypeHandle parent1) {
-  TypeHandle type_handle =
-    TypeRegistry::ptr()->register_dynamic_type(name);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-  return type_handle;
-}
-INLINE TypeHandle
-register_dynamic_type(const string &name,
-                      TypeHandle parent1, TypeHandle parent2) {
-  TypeHandle type_handle =
-    TypeRegistry::ptr()->register_dynamic_type(name);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent2);
-  return type_handle;
-}
-INLINE TypeHandle
-register_dynamic_type(const string &name,
-                      TypeHandle parent1, TypeHandle parent2,
-                      TypeHandle parent3) {
-  TypeHandle type_handle =
-    TypeRegistry::ptr()->register_dynamic_type(name);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent2);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent3);
-  return type_handle;
-}
-INLINE TypeHandle
-register_dynamic_type(const string &name,
-                      TypeHandle parent1, TypeHandle parent2,
-                      TypeHandle parent3, TypeHandle parent4) {
-  TypeHandle type_handle =
-    TypeRegistry::ptr()->register_dynamic_type(name);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent1);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent2);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent3);
-  TypeRegistry::ptr()->record_derivation(type_handle, parent4);
-  return type_handle;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: _dcast_get_typehandle
-//  Description: Returns the TypeHandle associated with the type of
-//               the parameter, if it can be determined.  This is a
-//               support function for _dcast, below.
-////////////////////////////////////////////////////////////////////
-template<class WantType>
-INLINE TypeHandle
-_dcast_get_typehandle(WantType *) {
-  TypeHandle handle = WantType::get_class_type();
-  if (handle == TypeHandle::none()) {
-    // This type handle is unregistered.  Oops!
-    WantType::init_type();
-    handle = WantType::get_class_type();
-    express_cat->warning()
-      << "Type " << handle << " was unregistered!\n";
-  }
-  return handle;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: _dcast
-//  Description: The implementation of the DCAST macro, this checks
-//               the actual type of the pointer before performing a
-//               downcast operation.  In NDEBUG mode, it simply
-//               downcasts.
-//
-//               This flavor of _dcast works on non-const pointers.
-////////////////////////////////////////////////////////////////////
-template<class WantType>
-INLINE WantType *
-_dcast(WantType *, TypedObject *ptr) {
-#ifndef NDEBUG
-  TypeHandle want_handle = _dcast_get_typehandle((WantType *)0);
- #if defined(_DEBUG) && defined(_WIN32)
-  if ((ptr == (TypedObject *)NULL) || IsBadWritePtr(ptr,sizeof(TypedObject))) {
- #else
-  if (ptr == (TypedObject *)NULL) {
- #endif
-    express_cat->warning()
-      << "Attempt to cast NULL pointer to " << want_handle << "\n";
-    return (WantType *)NULL;
-  }
-  if (!ptr->is_of_type(want_handle)) {
-    express_cat->error()
-      << "Attempt to cast pointer from " << ptr->get_type()
-      << " to " << want_handle << "\n";
-    if (ptr->get_type() == TypedObject::get_class_type()) {
-      express_cat->error(false)
-        << "Perhaps pointer was inadvertently deleted?\n";
-    }
-    return (WantType *)NULL;
-  }
-#endif
-  return (WantType *)ptr;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: _dcast
-//  Description: The implementation of the DCAST macro, this checks
-//               the actual type of the pointer before performing a
-//               downcast operation.  In NDEBUG mode, it simply
-//               downcasts.
-//
-//               This flavor of _dcast works on const pointers.
-////////////////////////////////////////////////////////////////////
-template<class WantType>
-INLINE const WantType *
-_dcast(WantType *, const TypedObject *ptr) {
-#ifndef NDEBUG
-  TypeHandle want_handle = _dcast_get_typehandle((WantType *)0);
-  if (ptr == (const TypedObject *)NULL) {
-    express_cat->warning()
-      << "Attempt to cast NULL pointer to " << want_handle << "\n";
-    return (const WantType *)NULL;
-  }
-  if (!ptr->is_of_type(want_handle)) {
-    express_cat->error()
-      << "Attempt to cast pointer from " << ptr->get_type()
-      << " to " << want_handle << "\n";
-    if (ptr->get_type() == TypedObject::get_class_type()) {
-      express_cat->error(false)
-        << "Perhaps pointer was inadvertently deleted?\n";
-    }
-    return (const WantType *)NULL;
-  }
-#endif
-  return (const WantType *)ptr;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: _dcast_ref
-//  Description: Similar to the above, with a pointer reference as the
-//               first parameter.  Just for fiddly compiler reasons;
-//               the reference isn't used.
-////////////////////////////////////////////////////////////////////
-template<class WantType>
-INLINE WantType *
-_dcast_ref(WantType *&, TypedObject *ptr) {
-  return _dcast((WantType *)NULL, ptr);
-}
-
-template<class WantType>
-INLINE const WantType *
-_dcast_ref(WantType *&, const TypedObject *ptr) {
-  return _dcast((WantType *)NULL, ptr);
-}

+ 0 - 681
panda/src/express/typeHandle.cxx

@@ -17,687 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "typeHandle.h"
-#include "typedObject.h"
-#include "indent.h"
-#include "config_express.h"
-
-#include <algorithm>
-
-// In general, we use the express_cat->info() syntax in this file
-// (instead of express_cat.info()), because much of this work is done at
-// static init time, and we must use the arrow syntax to force
-// initialization of the express_cat category.
-
-TypeRegistry *TypeRegistry::_global_pointer = NULL;
 
 // This is initialized to zero by static initialization.
 TypeHandle TypeHandle::_none;
-
-
-TypeHandle long_type_handle;
-TypeHandle int_type_handle;
-TypeHandle short_type_handle;
-TypeHandle char_type_handle;
-TypeHandle bool_type_handle;
-TypeHandle double_type_handle;
-TypeHandle float_type_handle;
-
-TypeHandle long_p_type_handle;
-TypeHandle int_p_type_handle;
-TypeHandle short_p_type_handle;
-TypeHandle char_p_type_handle;
-TypeHandle bool_p_type_handle;
-TypeHandle double_p_type_handle;
-TypeHandle float_p_type_handle;
-TypeHandle void_p_type_handle;
-
-void init_system_type_handles() {
-  static bool done = false;
-  if (!done) {
-    done = true;
-    register_type(long_type_handle, "long");
-    register_type(int_type_handle, "int");
-    register_type(short_type_handle, "short");
-    register_type(char_type_handle, "char");
-    register_type(bool_type_handle, "bool");
-    register_type(double_type_handle, "double");
-    register_type(float_type_handle, "float");
-
-    register_type(int_p_type_handle, "int*");
-    register_type(short_p_type_handle, "short*");
-    register_type(char_p_type_handle, "char*");
-    register_type(bool_p_type_handle, "bool*");
-    register_type(double_p_type_handle, "double*");
-    register_type(float_p_type_handle, "float*");
-    register_type(void_p_type_handle, "void*");
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::RegistryNode::Constructor
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-TypeRegistry::RegistryNode::
-RegistryNode(TypeHandle handle, const string &name, TypeHandle &ref) :
-  _handle(handle), _name(name), _ref(ref) {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::register_type
-//       Access: Public
-//  Description: Creates a new Type of the given name and assigns a
-//               unique value to the type_handle.  All type names must
-//               be unique.  If the type name has already been used,
-//               the supplied type_handle value must match the name's
-//               assigned type_handle or an error is triggered.
-//               Returns true if the name wasn't defined before, false
-//               if it was.
-////////////////////////////////////////////////////////////////////
-bool TypeRegistry::
-register_type(TypeHandle &type_handle, const string &name) {
-  if (type_handle != TypeHandle::none()) {
-    // Here's a type that was already registered.  Just make sure
-    // everything's still kosher.
-    RegistryNode *rnode = look_up(type_handle, NULL);
-    if (&type_handle == &rnode->_ref) {
-      // No problem.
-      nassertr(rnode->_name == name, false);
-      return false;
-    }
-  }
-
-  NameRegistry::iterator ri;
-  ri = _name_registry.find(name);
-
-  if (ri == _name_registry.end()) {
-    // The name was not already used; this is the first time this
-    // class has been defined.
-
-#ifdef NOTIFY_DEBUG
-    // This code runs at static init time, so cannot use the
-    // express_cat.is_spam() syntax.
-    if (express_cat->is_spam()) {
-      express_cat->spam() << "Registering type " << name << "\n";
-    }
-#endif
-
-    TypeHandle new_handle;
-    new_handle._index = _handle_registry.size();
-
-    RegistryNode *rnode = new RegistryNode(new_handle, name, type_handle);
-    _handle_registry.push_back(rnode);
-    _name_registry[name] = rnode;
-
-    type_handle = new_handle;
-    return true;
-  }
-  RegistryNode *rnode = (*ri).second;
-  nassertr(rnode->_name == (*ri).first, false);
-  nassertr(rnode->_handle._index >= 0 &&
-           rnode->_handle._index < (int)_handle_registry.size(), false);
-  nassertr(_handle_registry[rnode->_handle._index] == rnode, false);
-  nassertr(rnode->_handle._index != 0, false);
-
-  // The name was previously used; make sure the type_handle matches.
-  if (&type_handle == &rnode->_ref) {
-    // Ok, this was just a repeated attempt to register the same type.
-
-    if (type_handle == rnode->_handle) {
-      // No problem.
-      return false;
-    }
-    // But wait--the type_handle has changed!  We kept a reference to
-    // the static _type_handle member in the class that was passed in
-    // at the first call to register_type(), and we got the same
-    // reference passed in this time, but now it's different!  Bad
-    // juju.
-    express_cat->error()
-      << "Reregistering " << name << "\n";
-    type_handle == rnode->_handle;
-    return false;
-  }
-
-  if (type_handle != rnode->_handle) {
-    // Hmm, we seem to have a contradictory type registration!
-    express_cat->warning()
-      << "Attempt to register type " << name << " more than once!\n";
-
-    // This is invalid, but we'll allow it anyway.  It seems to happen
-    // for some reason under GNU libc5 that we occasionally end up
-    // with two legitimate copies of the same class object in
-    // memory--each with its own static _type_handle member.
-
-    type_handle = rnode->_handle;
-  }
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::register_dynamic_type
-//       Access: Public
-//  Description: Registers a new type on-the-fly, presumably at
-//               runtime.  A new TypeHandle is returned if the
-//               typename was not seen before; otherwise the same
-//               TypeHandle that was last used for this typename is
-//               returned.
-////////////////////////////////////////////////////////////////////
-TypeHandle TypeRegistry::
-register_dynamic_type(const string &name) {
-  NameRegistry::iterator ri;
-  ri = _name_registry.find(name);
-
-  if (ri == _name_registry.end()) {
-    // The name was not already used; this is the first time this
-    // class has been defined.
-
-#ifdef NOTIFY_DEBUG
-    // This code runs at static init time, so cannot use the
-    // express_cat.is_spam() syntax.
-    if (express_cat->is_spam()) {
-      express_cat->spam() << "Registering type " << name << "\n";
-    }
-#endif
-
-    // We must dynamically allocate a new handle so the RegistryNode
-    // has something unique to point to.  This doesn't really mean
-    // anything, though.
-    TypeHandle *new_handle = new TypeHandle;
-    new_handle->_index = _handle_registry.size();
-
-    RegistryNode *rnode = new RegistryNode(*new_handle, name, *new_handle);
-    _handle_registry.push_back(rnode);
-    _name_registry[name] = rnode;
-
-    return *new_handle;
-  }
-
-  // Return the TypeHandle previously obtained.
-  RegistryNode *rnode = (*ri).second;
-  return rnode->_handle;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::record_derivation
-//       Access: Public
-//  Description: Records that the type referenced by child inherits
-//               directly from the type referenced by parent.  In the
-//               event of multiple inheritance, this should be called
-//               once for each parent class.
-////////////////////////////////////////////////////////////////////
-void TypeRegistry::
-record_derivation(TypeHandle child, TypeHandle parent) {
-  RegistryNode *cnode = look_up(child, NULL);
-  nassertv(cnode != (RegistryNode *)NULL);
-  RegistryNode *pnode = look_up(parent, NULL);
-  nassertv(pnode != (RegistryNode *)NULL);
-
-  // First, we'll just run through the list to make sure we hadn't
-  // already made this connection.
-  RegistryNode::Classes::iterator ni;
-  ni = find(cnode->_parent_classes.begin(), cnode->_parent_classes.end(),
-            pnode);
-
-  if (ni == cnode->_parent_classes.end()) {
-    cnode->_parent_classes.push_back(pnode);
-    pnode->_child_classes.push_back(cnode);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::record_alternate_name
-//       Access: Public
-//  Description: Indicates an alternate name for the same type.  This
-//               is particularly useful when a type has changed names,
-//               since the type is stored in a Bam file by name;
-//               setting the original name as the alternate will allow
-//               the type to be correctly read from old Bam files.
-////////////////////////////////////////////////////////////////////
-void TypeRegistry::
-record_alternate_name(TypeHandle type, const string &name) {
-  RegistryNode *rnode = look_up(type, (TypedObject *)NULL);
-  if (rnode != (RegistryNode *)NULL) {
-    NameRegistry::iterator ri =
-      _name_registry.insert(NameRegistry::value_type(name, rnode)).first;
-    if ((*ri).second != rnode) {
-      express_cat.warning()
-        << "Name " << name << " already assigned to TypeHandle "
-        << rnode->_name << "; cannot reassign to " << type << "\n";
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::find_type
-//       Access: Public
-//  Description: Looks for a previously-registered type of the given
-//               name.  Returns its TypeHandle if it exists, or
-//               TypeHandle::none() if there is no such type.
-////////////////////////////////////////////////////////////////////
-TypeHandle TypeRegistry::
-find_type(const string &name) const {
-  NameRegistry::const_iterator ri;
-  ri = _name_registry.find(name);
-  if (ri == _name_registry.end()) {
-    return TypeHandle::none();
-  } else {
-    return (*ri).second->_handle;
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_name
-//       Access: Public
-//  Description: Returns the name of the indicated type.
-//
-//               The "object" pointer is an optional pointer to the
-//               TypedObject class that owns this TypeHandle.  It is
-//               only used in case the TypeHandle is inadvertantly
-//               undefined.
-////////////////////////////////////////////////////////////////////
-string TypeRegistry::
-get_name(TypeHandle type, TypedObject *object) const {
-  RegistryNode *rnode = look_up(type, object);
-  nassertr(rnode != (RegistryNode *)NULL, "");
-  return rnode->_name;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::is_derived_from
-//       Access: Public
-//  Description: Returns true if the first type is derived from the
-//               second type, false otherwise.
-//
-//               The "object" pointer is an optional pointer to the
-//               TypedObject class that owns this TypeHandle.  It is
-//               only used in case the TypeHandle is inadvertantly
-//               undefined.
-////////////////////////////////////////////////////////////////////
-bool TypeRegistry::
-is_derived_from(TypeHandle child, TypeHandle parent,
-                TypedObject *child_object) const {
-  RegistryNode *rnode = look_up(child, child_object);
-  nassertr(rnode != (RegistryNode *)NULL, false);
-  return rnode->is_derived_from(parent);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_num_root_classes
-//       Access: Public
-//  Description: Returns the number of root classes--that is, classes
-//               that do not inherit from any other classes--known in
-//               the system.
-////////////////////////////////////////////////////////////////////
-int TypeRegistry::
-get_num_root_classes() {
-  freshen_root_classes();
-  return _root_classes.size();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_root_class
-//       Access: Public
-//  Description: Returns the nth root class in the system.  See
-//               get_num_root_classes().
-////////////////////////////////////////////////////////////////////
-TypeHandle TypeRegistry::
-get_root_class(int n) {
-  freshen_root_classes();
-  nassertr(n >= 0 && n < get_num_root_classes(), TypeHandle::none());
-  return _root_classes[n]->_handle;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_num_parent_classes
-//       Access: Public
-//  Description: Returns the number of parent classes that the
-//               indicated type is known to have.  This may then be
-//               used to index into get_parent_class().  The result
-//               will be 0 if this class does not inherit from any
-//               other classes, 1 if normal, single inheritance is in
-//               effect, or greater than one if multiple inheritance
-//               is in effect.
-//
-//               The "object" pointer is an optional pointer to the
-//               TypedObject class that owns this TypeHandle.  It is
-//               only used in case the TypeHandle is inadvertantly
-//               undefined.
-////////////////////////////////////////////////////////////////////
-int TypeRegistry::
-get_num_parent_classes(TypeHandle child, TypedObject *child_object) const {
-  RegistryNode *rnode = look_up(child, child_object);
-  nassertr(rnode != (RegistryNode *)NULL, 0);
-  return rnode->_parent_classes.size();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_parent_class
-//       Access: Public
-//  Description: Returns the nth parent class of this type.  The index
-//               should be in the range 0 <= index <
-//               get_num_parent_classes().
-////////////////////////////////////////////////////////////////////
-TypeHandle TypeRegistry::
-get_parent_class(TypeHandle child, int index) const {
-  RegistryNode *rnode = look_up(child, (TypedObject *)NULL);
-  nassertr(rnode != (RegistryNode *)NULL, TypeHandle::none());
-  nassertr(index >= 0 && index < (int)rnode->_parent_classes.size(),
-           TypeHandle::none());
-  return rnode->_parent_classes[index]->_handle;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_num_child_classes
-//       Access: Public
-//  Description: Returns the number of child classes that the
-//               indicated type is known to have.  This may then be
-//               used to index into get_child_class().
-//
-//               The "object" pointer is an optional pointer to the
-//               TypedObject class that owns this TypeHandle.  It is
-//               only used in case the TypeHandle is inadvertantly
-//               undefined.
-////////////////////////////////////////////////////////////////////
-int TypeRegistry::
-get_num_child_classes(TypeHandle child, TypedObject *child_object) const {
-  RegistryNode *rnode = look_up(child, child_object);
-  nassertr(rnode != (RegistryNode *)NULL, 0);
-  return rnode->_child_classes.size();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_child_class
-//       Access: Public
-//  Description: Returns the nth child class of this type.  The index
-//               should be in the range 0 <= index <
-//               get_num_child_classes().
-////////////////////////////////////////////////////////////////////
-TypeHandle TypeRegistry::
-get_child_class(TypeHandle child, int index) const {
-  RegistryNode *rnode = look_up(child, (TypedObject *)NULL);
-  nassertr(rnode != (RegistryNode *)NULL, TypeHandle::none());
-  nassertr(index >= 0 && index < (int)rnode->_child_classes.size(),
-           TypeHandle::none());
-  return rnode->_child_classes[index]->_handle;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::get_parent_towards
-//       Access: Public
-//  Description: Returns the parent of the indicated child class that
-//               is in a direct line of inheritance to the indicated
-//               ancestor class.  This is useful in the presence of
-//               multiple inheritance to try to determine what
-//               properties an unknown type may have.
-//
-//               The "object" pointer is an optional pointer to the
-//               TypedObject class that owns this TypeHandle.  It is
-//               only used in case the TypeHandle is inadvertantly
-//               undefined.
-////////////////////////////////////////////////////////////////////
-TypeHandle TypeRegistry::
-get_parent_towards(TypeHandle child, TypeHandle ancestor,
-                   TypedObject *child_object) const {
-  if (child_object != (TypedObject *)NULL) {
-    // First, guarantee that the ancestor type is defined.
-    look_up(ancestor, child_object);
-  }
-  RegistryNode *rnode = look_up(child, child_object);
-  nassertr(rnode != (RegistryNode *)NULL, TypeHandle::none());
-  return rnode->get_parent_towards(ancestor);
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::reregister_types
-//       Access: Public, Static
-//  Description: Walks through the TypeRegistry tree and makes sure
-//               that each type that was previously registered is
-//               *still* registered.  This seems to get broken in
-//               certain circumstances when compiled against libc5--it
-//               is as if the static initializer stomps on the
-//               _type_handle values of each class after they've been
-//               registered.
-////////////////////////////////////////////////////////////////////
-void TypeRegistry::
-reregister_types() {
-  HandleRegistry::iterator ri;
-  TypeRegistry *reg = ptr();
-  for (ri = reg->_handle_registry.begin();
-       ri != reg->_handle_registry.end();
-       ++ri) {
-    RegistryNode *rnode = (*ri);
-    if (rnode != NULL && rnode->_handle != rnode->_ref) {
-      express_cat->warning()
-        << "Reregistering " << rnode->_name << "\n";
-    }
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::write
-//       Access: Public
-//  Description: Makes an attempt to format the entire TypeRegistry in
-//               a nice way that shows the derivation tree as
-//               intelligently as possible.
-////////////////////////////////////////////////////////////////////
-void TypeRegistry::
-write(ostream &out) const {
-  // Recursively write out the tree, starting from each node that has
-  // no parent.
-  HandleRegistry::const_iterator hi;
-  for (hi = _handle_registry.begin();
-       hi != _handle_registry.end();
-       ++hi) {
-    const RegistryNode *root = *hi;
-    if (root != NULL && root->_parent_classes.empty()) {
-      write_node(out, 2, root);
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::ptr
-//       Access: Public, Static
-//  Description: Returns the pointer to the global TypeRegistry
-//               object.
-////////////////////////////////////////////////////////////////////
-TypeRegistry *TypeRegistry::
-ptr() {
-  if (_global_pointer == NULL) {
-    init_global_pointer();
-  }
-  return _global_pointer;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::Constructor
-//       Access: Private
-//  Description:
-////////////////////////////////////////////////////////////////////
-TypeRegistry::
-TypeRegistry() {
-  // We'll start out our handle_registry with a default entry for the
-  // TypeHandles whose index number is zero, and are therefore
-  // (probably) uninitialized.
-  _handle_registry.push_back(NULL);
-
-  _root_classes_fresh = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::init_global_pointer
-//       Access: Private, Static
-//  Description: Constructs the TypeRegistry object for the first
-//               time.  It is initially created on the local heap,
-//               then as soon as shared memory becomes available, it
-//               should be moved into shared memory.
-////////////////////////////////////////////////////////////////////
-void TypeRegistry::
-init_global_pointer() {
-  _global_pointer = new TypeRegistry;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::freshen_root_classes
-//       Access: Private
-//  Description: Walks through the list of types registered, and adds
-//               any type known to be a root (that is, that derives
-//               from no other types) to the set of known root
-//               classes.  This must be done from time to time because
-//               we don't record this information when we initially
-//               record the types.
-////////////////////////////////////////////////////////////////////
-void TypeRegistry::
-freshen_root_classes() {
-  if (!_root_classes_fresh) {
-    _root_classes.clear();
-
-    HandleRegistry::iterator hi;
-    for (hi = _handle_registry.begin();
-         hi != _handle_registry.end();
-         ++hi) {
-      RegistryNode *root = *hi;
-      if (root != NULL && root->_parent_classes.empty()) {
-        _root_classes.push_back(root);
-      }
-    }
-    _root_classes_fresh = true;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::write_node
-//       Access: Private
-//  Description: Writes a single RegistryNode out, along with all of
-//               its descendants.
-////////////////////////////////////////////////////////////////////
-void TypeRegistry::
-write_node(ostream &out, int indent_level, const RegistryNode *node) const {
-  indent(out, indent_level) << node->_handle.get_index() << " " << node->_name;
-  if (!node->_parent_classes.empty()) {
-    out << " : " << node->_parent_classes[0]->_name;
-    for (int pi = 1; pi < (int)node->_parent_classes.size(); pi++) {
-      out << ", " << node->_parent_classes[pi]->_name;
-    }
-  }
-  out << "\n";
-
-  for (int i = 0; i < (int)node->_child_classes.size(); i++) {
-    write_node(out, indent_level + 2, node->_child_classes[i]);
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::look_up
-//       Access: Private
-//  Description: Returns the RegistryNode associated with the
-//               indicated TypeHandle.  If there is no associated
-//               RegistryNode, reports an error condition and aborts.
-//
-//               The associated TypedObject pointer is the pointer to
-//               the object that owns the handle, if available.  It is
-//               only used in an error condition, if for some reason
-//               the handle was uninitialized.
-////////////////////////////////////////////////////////////////////
-TypeRegistry::RegistryNode *TypeRegistry::
-look_up(TypeHandle handle, TypedObject *object) const {
-  if (handle._index == 0) {
-    // The TypeHandle is unregistered.  This is an error condition.
-
-    if (object != NULL) {
-      // But we're lucky enough to have a TypedObject pointer handy!
-      // Maybe we can use it to resolve the error.
-      handle = object->force_init_type();
-      if (handle._index == 0) {
-        // Strange.
-        express_cat->error()
-          << "Unable to force_init_type() on unregistered TypeHandle.\n";
-        nassertr(false, NULL);
-      }
-      if (handle == object->get_type()) {
-        // Problem solved!
-        express_cat->warning()
-          << "Type " << handle << " was unregistered!\n";
-      } else {
-        // No good; it looks like the TypeHandle belongs to a class
-        // that defined get_type(), but didn't define
-        // force_init_type().
-        express_cat->error()
-          << "Attempt to reference unregistered TypeHandle.  Type is of some\n"
-          << "class derived from " << handle << " that doesn't define a good\n"
-          << "force_init_type() method.\n";
-        nassertr(false, NULL);
-      }
-
-    } else {
-      // We don't have a TypedObject pointer, so there's nothing we
-      // can do about it.
-      express_cat->error()
-        << "Attempt to reference unregistered TypeHandle!\n"
-        << "Registered TypeHandles are:\n";
-      write(express_cat->error(false));
-      nassertr(false, NULL);
-    }
-  }
-
-  if (handle._index < 0 ||
-      handle._index >= (int)_handle_registry.size()) {
-    express_cat->fatal()
-      << "Invalid TypeHandle index " << handle._index
-      << "!  Is memory corrupt?\n";
-    nassertr(false, NULL);
-  }
-
-  return _handle_registry[handle._index];
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::RegistryNode::is_derived_from
-//       Access: Public
-//  Description: Returns true if the current RegistryNode represents a
-//               class of type TypeHandle, or any of its ancestors do.
-////////////////////////////////////////////////////////////////////
-bool TypeRegistry::RegistryNode::
-is_derived_from(TypeHandle type) const {
-  if (_handle == type) {
-    return true;
-  }
-
-  Classes::const_iterator ni;
-  for (ni = _parent_classes.begin(); ni != _parent_classes.end(); ++ni) {
-    if ((*ni)->is_derived_from(type)) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TypeRegistry::RegistryNode::get_parent_towards
-//       Access: Public
-//  Description: Returns the first derived class that is an descendant
-//               of the indicated ancestor class.
-////////////////////////////////////////////////////////////////////
-TypeHandle TypeRegistry::RegistryNode::
-get_parent_towards(TypeHandle type) const {
-  if (_handle == type) {
-    return type;
-  }
-
-  Classes::const_iterator ni;
-  for (ni = _parent_classes.begin(); ni != _parent_classes.end(); ++ni) {
-    if ((*ni)->is_derived_from(type)) {
-      return (*ni)->_handle;
-    }
-  }
-
-  return TypeHandle::none();
-}
-

+ 8 - 353
panda/src/express/typeHandle.h

@@ -19,15 +19,11 @@
 #ifndef TYPEHANDLE_H
 #define TYPEHANDLE_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
-#include <notify.h>
+#include "notify.h"
 
-#include <string>
-#include "pvector.h"
-#include "pmap.h"
-#include "pset.h"
-#include <stdlib.h>
+#include "config_express.h"
 
 // The following illustrates the convention for declaring a type that
 // uses TypeHandle.  In this example, ThisThingie inherits from
@@ -132,352 +128,11 @@ INLINE ostream &operator << (ostream &out, TypeHandle type) {
   return out << type.get_name();
 }
 
-////////////////////////////////////////////////////////////////////
-//       Class : TypeRegistry
-// Description : The TypeRegistry class maintains all the assigned
-//               TypeHandles in a given system.  There should be only
-//               one TypeRegistry class during the lifetime of the
-//               application.  It will be created on the local heap
-//               initially, and it should be migrated to shared memory
-//               as soon as shared memory becomes available.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDAEXPRESS TypeRegistry {
-protected:
-  class RegistryNode {
-  public:
-    RegistryNode(TypeHandle handle, const string &name, TypeHandle &ref);
-    bool is_derived_from(TypeHandle type) const;
-    TypeHandle get_parent_towards(TypeHandle type) const;
-
-    TypeHandle _handle;
-    string _name;
-    TypeHandle &_ref;
-    typedef pvector<RegistryNode *> Classes;
-    Classes _parent_classes;
-    Classes _child_classes;
-  };
-
-public:
-  // User code shouldn't generally need to call
-  // TypeRegistry::register_type() or record_derivation() directly;
-  // instead, use the register_type convenience function, defined
-  // below.
-  bool register_type(TypeHandle &type_handle, const string &name);
-  TypeHandle register_dynamic_type(const string &name);
-
-  void record_derivation(TypeHandle child, TypeHandle parent);
-  void record_alternate_name(TypeHandle type, const string &name);
-
-PUBLISHED:
-  TypeHandle find_type(const string &name) const;
-
-  string get_name(TypeHandle type, TypedObject *object) const;
-  bool is_derived_from(TypeHandle child, TypeHandle parent,
-                       TypedObject *child_object) const;
-
-  int get_num_root_classes();
-  TypeHandle get_root_class(int n);
-
-  int get_num_parent_classes(TypeHandle child,
-                             TypedObject *child_object) const;
-  TypeHandle get_parent_class(TypeHandle child, int index) const;
-
-  int get_num_child_classes(TypeHandle child,
-                            TypedObject *child_object) const;
-  TypeHandle get_child_class(TypeHandle child, int index) const;
-
-  TypeHandle get_parent_towards(TypeHandle child, TypeHandle ancestor,
-                                TypedObject *child_object) const;
-
-  static void reregister_types();
-
-  void write(ostream &out) const;
-
-  // ptr() returns the pointer to the global TypeRegistry object.
-  static TypeRegistry *ptr();
-
-private:
-  // The TypeRegistry class should never be constructed by user code.
-  // There is only one in the universe, and it constructs itself!
-  TypeRegistry();
-
-  static void init_global_pointer();
-
-  RegistryNode *look_up(TypeHandle type, TypedObject *object) const;
-
-  void freshen_root_classes();
-  void write_node(ostream &out, int indent_level,
-                  const RegistryNode *node) const;
-
-  typedef pvector<RegistryNode *> HandleRegistry;
-  HandleRegistry _handle_registry;
-
-  typedef pmap<string, RegistryNode *> NameRegistry;
-  NameRegistry _name_registry;
-
-  typedef pvector<RegistryNode *> RootClasses;
-  bool _root_classes_fresh;
-  RootClasses _root_classes;
-
-  static TypeRegistry *_global_pointer;
-};
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: register_type
-//  Description: This inline function is just a convenient way to call
-//               TypeRegistry::register_type(), along with zero to four
-//               record_derivation()s.  If for some reason you have a
-//               class that has more than four base classes (you're
-//               insane!), then you will need to call Register() and
-//               record_derivation() yourself.
-////////////////////////////////////////////////////////////////////
-INLINE void
-register_type(TypeHandle &type_handle, const string &name);
-
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1);
-
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1, TypeHandle parent2);
-
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1, TypeHandle parent2,
-              TypeHandle parent3);
-
-INLINE void
-register_type(TypeHandle &type_handle, const string &name,
-              TypeHandle parent1, TypeHandle parent2,
-              TypeHandle parent3, TypeHandle parent4);
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: register_dynamic_type
-//  Description: This is essentially similar to register_type(),
-//               except that it doesn't store a reference to any
-//               TypeHandle passed in and it therefore doesn't
-//               complain if the type is registered more than once to
-//               different TypeHandle reference.
-////////////////////////////////////////////////////////////////////
-INLINE TypeHandle
-register_dynamic_type(const string &name);
-
-INLINE TypeHandle
-register_dynamic_type(const string &name, TypeHandle parent1);
-
-INLINE TypeHandle
-register_dynamic_type(const string &name,
-                      TypeHandle parent1, TypeHandle parent2);
-
-INLINE TypeHandle
-register_dynamic_type(const string &name,
-                      TypeHandle parent1, TypeHandle parent2,
-                      TypeHandle parent3);
-
-INLINE TypeHandle
-register_dynamic_type(const string &name,
-                      TypeHandle parent1, TypeHandle parent2,
-                      TypeHandle parent3, TypeHandle parent4);
-
-
-// A few system-wide TypeHandles are defined for some basic types.
-extern TypeHandle EXPCL_PANDAEXPRESS long_type_handle;
-extern TypeHandle EXPCL_PANDAEXPRESS int_type_handle;
-extern TypeHandle EXPCL_PANDAEXPRESS short_type_handle;
-extern TypeHandle EXPCL_PANDAEXPRESS char_type_handle;
-extern TypeHandle EXPCL_PANDAEXPRESS bool_type_handle;
-extern TypeHandle EXPCL_PANDAEXPRESS double_type_handle;
-extern TypeHandle EXPCL_PANDAEXPRESS float_type_handle;
-
-extern TypeHandle long_p_type_handle;
-extern TypeHandle int_p_type_handle;
-extern TypeHandle short_p_type_handle;
-extern TypeHandle char_p_type_handle;
-extern TypeHandle bool_p_type_handle;
-extern TypeHandle double_p_type_handle;
-extern TypeHandle float_p_type_handle;
-extern TypeHandle void_p_type_handle;
-
-void EXPCL_PANDAEXPRESS init_system_type_handles();
-
-// The following template function and its specializations will return
-// a TypeHandle for any type in the world, from a pointer to that
-// type.
-
-template<class T>
-INLINE TypeHandle _get_type_handle(const T *) {
-  return T::get_class_type();
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const long *) {
-  return long_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const int *) {
-  return int_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const short *) {
-  return short_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const char *) {
-  return char_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const bool *) {
-  return bool_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const double *) {
-  return double_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const float *) {
-  return float_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const long * const *) {
-  return long_p_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const int * const *) {
-  return int_p_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const short * const *) {
-  return short_p_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const char * const *) {
-  return char_p_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const bool * const *) {
-  return bool_p_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const double * const *) {
-  return double_p_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const float * const *) {
-  return float_p_type_handle;
-}
-
-template<>
-INLINE TypeHandle _get_type_handle(const void * const *) {
-  return void_p_type_handle;
-}
-
-
-// The macro get_type_handle(type) is defined to make getting the type
-// handle associated with a particular type a bit cleaner.
-#define get_type_handle(type) _get_type_handle((const type *)0)
-
-
-// The following template function and its specializations can be used
-// to call init() on any unknown type.  Handy for use within a
-// template class.
-
-template<class T>
-INLINE void _do_init_type(const T *) {
-  T::init_type();
-}
-
-template<>
-INLINE void _do_init_type(const long *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const int *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const short *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const char *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const bool *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const double *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const float *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const long * const *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const int * const *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const short * const *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const char * const *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const bool * const *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const double * const *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const float * const *) {
-  init_system_type_handles();
-}
-
-template<>
-INLINE void _do_init_type(const void * const *) {
-  init_system_type_handles();
-}
-
-#define do_init_type(type) _do_init_type((const type *)0)
+// We must include typeRegistry at this point so we can call it from
+// our inline functions.  This is a circular include that is
+// strategically placed to do no harm.
+/* okcircular */
+#include "typeRegistry.h"
 
 #include "typeHandle.I"
 

+ 79 - 0
panda/src/express/typeRegistry.I

@@ -0,0 +1,79 @@
+// Filename: typeRegistry.I
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+#ifdef NDEBUG
+// This function is only inline if NDEBUG is defined.  Otherwise, it
+// is non-inline and its definition appears in typeRegistry.cxx.
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::look_up
+//       Access: Private
+//  Description: Returns the TypeRegistryNode associated with the
+//               indicated TypeHandle.
+////////////////////////////////////////////////////////////////////
+INLINE TypeRegistry::TypeRegistryNode *TypeRegistry::
+look_up(TypeHandle handle, TypedObject *) const {
+  return _handle_registry[handle._index];
+}
+#endif  // NDEBUG
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::freshen_derivations
+//       Access: Private
+//  Description: Rebuilds the derivation data structures after some
+//               derivation relationship has been modified, so that
+//               class relationships can quickly be determined.
+////////////////////////////////////////////////////////////////////
+INLINE void TypeRegistry::
+freshen_derivations() {
+  if (!_derivations_fresh) {
+    rebuild_derivations();
+    _derivations_fresh = true;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::is_derived_from
+//       Access: Public
+//  Description: Returns true if the first type is derived from the
+//               second type, false otherwise.
+//
+//               The "child_object" pointer is an optional pointer to
+//               the TypedObject class that owns the child TypeHandle.
+//               It is only used in case the TypeHandle is
+//               inadvertently undefined.
+//
+//               This function definition follows the definitions for
+//               look_up() and freshen_derivations() just to maximize
+//               the chance the the compiler will be able to inline
+//               the above functions.  Yeah, a compiler shouldn't
+//               care, but there's a big different between "shouldn't"
+//               and "doesn't".
+////////////////////////////////////////////////////////////////////
+INLINE bool TypeRegistry::
+is_derived_from(TypeHandle child, TypeHandle base,
+                TypedObject *child_object) {
+  const TypeRegistryNode *child_node = look_up(child, child_object);
+  const TypeRegistryNode *base_node = look_up(base, NULL);
+  nassertr(child_node != (TypeRegistryNode *)NULL &&
+           base_node != (TypeRegistryNode *)NULL, false);
+  freshen_derivations();
+  return TypeRegistryNode::is_derived_from(child_node, base_node);
+}

+ 608 - 0
panda/src/express/typeRegistry.cxx

@@ -0,0 +1,608 @@
+// Filename: typeRegistry.cxx
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "typeRegistry.h"
+#include "typedObject.h"
+#include "indent.h"
+#include "config_express.h"
+
+#include <algorithm>
+
+// In general, we use the express_cat->info() syntax in this file
+// (instead of express_cat.info()), because much of this work is done at
+// static init time, and we must use the arrow syntax to force
+// initialization of the express_cat category.
+
+TypeRegistry *TypeRegistry::_global_pointer = NULL;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::register_type
+//       Access: Public
+//  Description: Creates a new Type of the given name and assigns a
+//               unique value to the type_handle.  All type names must
+//               be unique.  If the type name has already been used,
+//               the supplied type_handle value must match the name's
+//               assigned type_handle or an error is triggered.
+//               Returns true if the name wasn't defined before, false
+//               if it was.
+////////////////////////////////////////////////////////////////////
+bool TypeRegistry::
+register_type(TypeHandle &type_handle, const string &name) {
+  if (type_handle != TypeHandle::none()) {
+    // Here's a type that was already registered.  Just make sure
+    // everything's still kosher.
+    TypeRegistryNode *rnode = look_up(type_handle, NULL);
+    if (&type_handle == &rnode->_ref) {
+      // No problem.
+      nassertr(rnode->_name == name, false);
+      return false;
+    }
+  }
+
+  NameRegistry::iterator ri;
+  ri = _name_registry.find(name);
+
+  if (ri == _name_registry.end()) {
+    // The name was not already used; this is the first time this
+    // class has been defined.
+
+#ifdef NOTIFY_DEBUG
+    // This code runs at static init time, so cannot use the
+    // express_cat.is_spam() syntax.
+    if (express_cat->is_spam()) {
+      express_cat->spam() << "Registering type " << name << "\n";
+    }
+#endif
+
+    TypeHandle new_handle;
+    new_handle._index = _handle_registry.size();
+
+    TypeRegistryNode *rnode = new TypeRegistryNode(new_handle, name, type_handle);
+    _handle_registry.push_back(rnode);
+    _name_registry[name] = rnode;
+    _derivations_fresh = false;
+
+    type_handle = new_handle;
+    return true;
+  }
+  TypeRegistryNode *rnode = (*ri).second;
+  nassertr(rnode->_name == (*ri).first, false);
+  nassertr(rnode->_handle._index >= 0 &&
+           rnode->_handle._index < (int)_handle_registry.size(), false);
+  nassertr(_handle_registry[rnode->_handle._index] == rnode, false);
+  nassertr(rnode->_handle._index != 0, false);
+
+  // The name was previously used; make sure the type_handle matches.
+  if (&type_handle == &rnode->_ref) {
+    // Ok, this was just a repeated attempt to register the same type.
+
+    if (type_handle == rnode->_handle) {
+      // No problem.
+      return false;
+    }
+    // But wait--the type_handle has changed!  We kept a reference to
+    // the static _type_handle member in the class that was passed in
+    // at the first call to register_type(), and we got the same
+    // reference passed in this time, but now it's different!  Bad
+    // juju.
+    express_cat->error()
+      << "Reregistering " << name << "\n";
+    type_handle == rnode->_handle;
+    return false;
+  }
+
+  if (type_handle != rnode->_handle) {
+    // Hmm, we seem to have a contradictory type registration!
+    express_cat->warning()
+      << "Attempt to register type " << name << " more than once!\n";
+
+    // This is invalid, but we'll allow it anyway.  It seems to happen
+    // for some reason under GNU libc5 that we occasionally end up
+    // with two legitimate copies of the same class object in
+    // memory--each with its own static _type_handle member.
+
+    type_handle = rnode->_handle;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::register_dynamic_type
+//       Access: Public
+//  Description: Registers a new type on-the-fly, presumably at
+//               runtime.  A new TypeHandle is returned if the
+//               typename was not seen before; otherwise the same
+//               TypeHandle that was last used for this typename is
+//               returned.
+////////////////////////////////////////////////////////////////////
+TypeHandle TypeRegistry::
+register_dynamic_type(const string &name) {
+  NameRegistry::iterator ri;
+  ri = _name_registry.find(name);
+
+  if (ri == _name_registry.end()) {
+    // The name was not already used; this is the first time this
+    // class has been defined.
+
+#ifdef NOTIFY_DEBUG
+    // This code runs at static init time, so cannot use the
+    // express_cat.is_spam() syntax.
+    if (express_cat->is_spam()) {
+      express_cat->spam() << "Registering type " << name << "\n";
+    }
+#endif
+
+    // We must dynamically allocate a new handle so the TypeRegistryNode
+    // has something unique to point to.  This doesn't really mean
+    // anything, though.
+    TypeHandle *new_handle = new TypeHandle;
+    new_handle->_index = _handle_registry.size();
+
+    TypeRegistryNode *rnode = new TypeRegistryNode(*new_handle, name, *new_handle);
+    _handle_registry.push_back(rnode);
+    _name_registry[name] = rnode;
+    _derivations_fresh = false;
+
+    return *new_handle;
+  }
+
+  // Return the TypeHandle previously obtained.
+  TypeRegistryNode *rnode = (*ri).second;
+  return rnode->_handle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::record_derivation
+//       Access: Public
+//  Description: Records that the type referenced by child inherits
+//               directly from the type referenced by parent.  In the
+//               event of multiple inheritance, this should be called
+//               once for each parent class.
+////////////////////////////////////////////////////////////////////
+void TypeRegistry::
+record_derivation(TypeHandle child, TypeHandle parent) {
+  TypeRegistryNode *cnode = look_up(child, NULL);
+  nassertv(cnode != (TypeRegistryNode *)NULL);
+  TypeRegistryNode *pnode = look_up(parent, NULL);
+  nassertv(pnode != (TypeRegistryNode *)NULL);
+
+  // First, we'll just run through the list to make sure we hadn't
+  // already made this connection.
+  TypeRegistryNode::Classes::iterator ni;
+  ni = find(cnode->_parent_classes.begin(), cnode->_parent_classes.end(),
+            pnode);
+
+  if (ni == cnode->_parent_classes.end()) {
+    cnode->_parent_classes.push_back(pnode);
+    pnode->_child_classes.push_back(cnode);
+    _derivations_fresh = false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::record_alternate_name
+//       Access: Public
+//  Description: Indicates an alternate name for the same type.  This
+//               is particularly useful when a type has changed names,
+//               since the type is stored in a Bam file by name;
+//               setting the original name as the alternate will allow
+//               the type to be correctly read from old Bam files.
+////////////////////////////////////////////////////////////////////
+void TypeRegistry::
+record_alternate_name(TypeHandle type, const string &name) {
+  TypeRegistryNode *rnode = look_up(type, (TypedObject *)NULL);
+  if (rnode != (TypeRegistryNode *)NULL) {
+    NameRegistry::iterator ri =
+      _name_registry.insert(NameRegistry::value_type(name, rnode)).first;
+    if ((*ri).second != rnode) {
+      express_cat.warning()
+        << "Name " << name << " already assigned to TypeHandle "
+        << rnode->_name << "; cannot reassign to " << type << "\n";
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::find_type
+//       Access: Public
+//  Description: Looks for a previously-registered type of the given
+//               name.  Returns its TypeHandle if it exists, or
+//               TypeHandle::none() if there is no such type.
+////////////////////////////////////////////////////////////////////
+TypeHandle TypeRegistry::
+find_type(const string &name) const {
+  NameRegistry::const_iterator ri;
+  ri = _name_registry.find(name);
+  if (ri == _name_registry.end()) {
+    return TypeHandle::none();
+  } else {
+    return (*ri).second->_handle;
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_name
+//       Access: Public
+//  Description: Returns the name of the indicated type.
+//
+//               The "object" pointer is an optional pointer to the
+//               TypedObject class that owns this TypeHandle.  It is
+//               only used in case the TypeHandle is inadvertantly
+//               undefined.
+////////////////////////////////////////////////////////////////////
+string TypeRegistry::
+get_name(TypeHandle type, TypedObject *object) const {
+  TypeRegistryNode *rnode = look_up(type, object);
+  nassertr(rnode != (TypeRegistryNode *)NULL, "");
+  return rnode->_name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_num_root_classes
+//       Access: Public
+//  Description: Returns the number of root classes--that is, classes
+//               that do not inherit from any other classes--known in
+//               the system.
+////////////////////////////////////////////////////////////////////
+int TypeRegistry::
+get_num_root_classes() {
+  freshen_derivations();
+  return _root_classes.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_root_class
+//       Access: Public
+//  Description: Returns the nth root class in the system.  See
+//               get_num_root_classes().
+////////////////////////////////////////////////////////////////////
+TypeHandle TypeRegistry::
+get_root_class(int n) {
+  freshen_derivations();
+  nassertr(n >= 0 && n < get_num_root_classes(), TypeHandle::none());
+  return _root_classes[n]->_handle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_num_parent_classes
+//       Access: Public
+//  Description: Returns the number of parent classes that the
+//               indicated type is known to have.  This may then be
+//               used to index into get_parent_class().  The result
+//               will be 0 if this class does not inherit from any
+//               other classes, 1 if normal, single inheritance is in
+//               effect, or greater than one if multiple inheritance
+//               is in effect.
+//
+//               The "object" pointer is an optional pointer to the
+//               TypedObject class that owns this TypeHandle.  It is
+//               only used in case the TypeHandle is inadvertantly
+//               undefined.
+////////////////////////////////////////////////////////////////////
+int TypeRegistry::
+get_num_parent_classes(TypeHandle child, TypedObject *child_object) const {
+  TypeRegistryNode *rnode = look_up(child, child_object);
+  nassertr(rnode != (TypeRegistryNode *)NULL, 0);
+  return rnode->_parent_classes.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_parent_class
+//       Access: Public
+//  Description: Returns the nth parent class of this type.  The index
+//               should be in the range 0 <= index <
+//               get_num_parent_classes().
+////////////////////////////////////////////////////////////////////
+TypeHandle TypeRegistry::
+get_parent_class(TypeHandle child, int index) const {
+  TypeRegistryNode *rnode = look_up(child, (TypedObject *)NULL);
+  nassertr(rnode != (TypeRegistryNode *)NULL, TypeHandle::none());
+  nassertr(index >= 0 && index < (int)rnode->_parent_classes.size(),
+           TypeHandle::none());
+  return rnode->_parent_classes[index]->_handle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_num_child_classes
+//       Access: Public
+//  Description: Returns the number of child classes that the
+//               indicated type is known to have.  This may then be
+//               used to index into get_child_class().
+//
+//               The "object" pointer is an optional pointer to the
+//               TypedObject class that owns this TypeHandle.  It is
+//               only used in case the TypeHandle is inadvertantly
+//               undefined.
+////////////////////////////////////////////////////////////////////
+int TypeRegistry::
+get_num_child_classes(TypeHandle child, TypedObject *child_object) const {
+  TypeRegistryNode *rnode = look_up(child, child_object);
+  nassertr(rnode != (TypeRegistryNode *)NULL, 0);
+  return rnode->_child_classes.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_child_class
+//       Access: Public
+//  Description: Returns the nth child class of this type.  The index
+//               should be in the range 0 <= index <
+//               get_num_child_classes().
+////////////////////////////////////////////////////////////////////
+TypeHandle TypeRegistry::
+get_child_class(TypeHandle child, int index) const {
+  TypeRegistryNode *rnode = look_up(child, (TypedObject *)NULL);
+  nassertr(rnode != (TypeRegistryNode *)NULL, TypeHandle::none());
+  nassertr(index >= 0 && index < (int)rnode->_child_classes.size(),
+           TypeHandle::none());
+  return rnode->_child_classes[index]->_handle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::get_parent_towards
+//       Access: Public
+//  Description: Returns the parent of the indicated child class that
+//               is in a direct line of inheritance to the indicated
+//               ancestor class.  This is useful in the presence of
+//               multiple inheritance to try to determine what
+//               properties an unknown type may have.
+//
+//               The "object" pointer is an optional pointer to the
+//               TypedObject class that owns this TypeHandle.  It is
+//               only used in case the TypeHandle is inadvertantly
+//               undefined.
+////////////////////////////////////////////////////////////////////
+TypeHandle TypeRegistry::
+get_parent_towards(TypeHandle child, TypeHandle base,
+                   TypedObject *child_object) const {
+  const TypeRegistryNode *child_node = look_up(child, child_object);
+  const TypeRegistryNode *base_node = look_up(base, NULL);
+  nassertr(child_node != (TypeRegistryNode *)NULL && 
+           base_node != (TypeRegistryNode *)NULL, TypeHandle::none());
+  return TypeRegistryNode::get_parent_towards(child_node, base_node);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::reregister_types
+//       Access: Public, Static
+//  Description: Walks through the TypeRegistry tree and makes sure
+//               that each type that was previously registered is
+//               *still* registered.  This seems to get broken in
+//               certain circumstances when compiled against libc5--it
+//               is as if the static initializer stomps on the
+//               _type_handle values of each class after they've been
+//               registered.
+////////////////////////////////////////////////////////////////////
+void TypeRegistry::
+reregister_types() {
+  HandleRegistry::iterator ri;
+  TypeRegistry *reg = ptr();
+  for (ri = reg->_handle_registry.begin();
+       ri != reg->_handle_registry.end();
+       ++ri) {
+    TypeRegistryNode *rnode = (*ri);
+    if (rnode != NULL && rnode->_handle != rnode->_ref) {
+      express_cat->warning()
+        << "Reregistering " << rnode->_name << "\n";
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::write
+//       Access: Public
+//  Description: Makes an attempt to format the entire TypeRegistry in
+//               a nice way that shows the derivation tree as
+//               intelligently as possible.
+////////////////////////////////////////////////////////////////////
+void TypeRegistry::
+write(ostream &out) const {
+  // Recursively write out the tree, starting from each node that has
+  // no parent.
+  HandleRegistry::const_iterator hi;
+  for (hi = _handle_registry.begin();
+       hi != _handle_registry.end();
+       ++hi) {
+    const TypeRegistryNode *root = *hi;
+    if (root != NULL && root->_parent_classes.empty()) {
+      write_node(out, 2, root);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::ptr
+//       Access: Public, Static
+//  Description: Returns the pointer to the global TypeRegistry
+//               object.
+////////////////////////////////////////////////////////////////////
+TypeRegistry *TypeRegistry::
+ptr() {
+  if (_global_pointer == NULL) {
+    init_global_pointer();
+  }
+  return _global_pointer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::Constructor
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+TypeRegistry::
+TypeRegistry() {
+  // We'll start out our handle_registry with a default entry for the
+  // TypeHandles whose index number is zero, and are therefore
+  // (probably) uninitialized.
+  _handle_registry.push_back(NULL);
+
+  _derivations_fresh = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::init_global_pointer
+//       Access: Private, Static
+//  Description: Constructs the TypeRegistry object for the first
+//               time.  It is initially created on the local heap,
+//               then as soon as shared memory becomes available, it
+//               should be moved into shared memory.
+////////////////////////////////////////////////////////////////////
+void TypeRegistry::
+init_global_pointer() {
+  _global_pointer = new TypeRegistry;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::rebuild_derivations
+//       Access: Private
+//  Description: Rebuilds the derivation data structures after some
+//               derivation relationship has been modified, so that
+//               class relationships can quickly be determined.
+////////////////////////////////////////////////////////////////////
+void TypeRegistry::
+rebuild_derivations() {
+#ifdef NOTIFY_DEBUG
+  express_cat->debug()
+    << "Rebuilding derivation tree.\n";
+#endif
+
+  // First, remove all of the old data from the last type
+  // rebuild_derivations() was called.
+  _root_classes.clear();
+
+  HandleRegistry::iterator hi;
+  for (hi = _handle_registry.begin();
+       hi != _handle_registry.end();
+       ++hi) {
+    TypeRegistryNode *node = *hi;
+    if (node != (TypeRegistryNode *)NULL) {
+      node->clear_subtree();
+    }
+  }
+  
+  // Start by getting the list of root classes: those classes which do
+  // not derive from anything.
+  for (hi = _handle_registry.begin();
+       hi != _handle_registry.end();
+       ++hi) {
+    TypeRegistryNode *node = *hi;
+    if (node != NULL && node->_parent_classes.empty()) {
+      _root_classes.push_back(node);
+
+      // Also, for each root class, define a subtree.
+      node->define_subtree();
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::write_node
+//       Access: Private
+//  Description: Writes a single TypeRegistryNode out, along with all of
+//               its descendants.
+////////////////////////////////////////////////////////////////////
+void TypeRegistry::
+write_node(ostream &out, int indent_level, const TypeRegistryNode *node) const {
+  indent(out, indent_level) << node->_handle.get_index() << " " << node->_name;
+  if (!node->_parent_classes.empty()) {
+    out << " : " << node->_parent_classes[0]->_name;
+    for (int pi = 1; pi < (int)node->_parent_classes.size(); pi++) {
+      out << ", " << node->_parent_classes[pi]->_name;
+    }
+  }
+  out << "\n";
+
+  for (int i = 0; i < (int)node->_child_classes.size(); i++) {
+    write_node(out, indent_level + 2, node->_child_classes[i]);
+  }
+}
+
+#ifndef NDEBUG
+// This function is only non-inline if NDEBUG is not defined.
+// Otherwise, it is inline and its definition appears in
+// typeRegistry.I.
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistry::look_up
+//       Access: Private
+//  Description: Returns the TypeRegistryNode associated with the
+//               indicated TypeHandle.  If there is no associated
+//               TypeRegistryNode, reports an error condition and
+//               returns NULL.
+//
+//               The associated TypedObject pointer is the pointer to
+//               the object that owns the handle, if available.  It is
+//               only used in an error condition, if for some reason
+//               the handle was uninitialized.
+////////////////////////////////////////////////////////////////////
+TypeRegistryNode *TypeRegistry::
+look_up(TypeHandle handle, TypedObject *object) const {
+  if (handle._index == 0) {
+    // The TypeHandle is unregistered.  This is an error condition.
+
+    if (object != NULL) {
+      // But we're lucky enough to have a TypedObject pointer handy!
+      // Maybe we can use it to resolve the error.
+      handle = object->force_init_type();
+      if (handle._index == 0) {
+        // Strange.
+        express_cat->error()
+          << "Unable to force_init_type() on unregistered TypeHandle.\n";
+        nassertr(false, NULL);
+      }
+      if (handle == object->get_type()) {
+        // Problem solved!
+        express_cat->warning()
+          << "Type " << handle << " was unregistered!\n";
+      } else {
+        // No good; it looks like the TypeHandle belongs to a class
+        // that defined get_type(), but didn't define
+        // force_init_type().
+        express_cat->error()
+          << "Attempt to reference unregistered TypeHandle.  Type is of some\n"
+          << "class derived from " << handle << " that doesn't define a good\n"
+          << "force_init_type() method.\n";
+        nassertr(false, NULL);
+      }
+
+    } else {
+      // We don't have a TypedObject pointer, so there's nothing we
+      // can do about it.
+      express_cat->error()
+        << "Attempt to reference unregistered TypeHandle!\n"
+        << "Registered TypeHandles are:\n";
+      write(express_cat->error(false));
+      nassertr(false, NULL);
+    }
+  }
+
+  if (handle._index < 0 ||
+      handle._index >= (int)_handle_registry.size()) {
+    express_cat->fatal()
+      << "Invalid TypeHandle index " << handle._index
+      << "!  Is memory corrupt?\n";
+    nassertr(false, NULL);
+  }
+
+  return _handle_registry[handle._index];
+}
+#endif  // NDEBUG
+

+ 116 - 0
panda/src/express/typeRegistry.h

@@ -0,0 +1,116 @@
+// Filename: typeRegistry.h
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef TYPEREGISTRY_H
+#define TYPEREGISTRY_H
+
+#include "pandabase.h"
+
+#include "typeHandle.h"
+#include "typeRegistryNode.h"
+
+#include "notify.h"
+#include "pvector.h"
+#include "pmap.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : TypeRegistry
+// Description : The TypeRegistry class maintains all the assigned
+//               TypeHandles in a given system.  There should be only
+//               one TypeRegistry class during the lifetime of the
+//               application.  It will be created on the local heap
+//               initially, and it should be migrated to shared memory
+//               as soon as shared memory becomes available.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS TypeRegistry {
+public:
+  // User code shouldn't generally need to call
+  // TypeRegistry::register_type() or record_derivation() directly;
+  // instead, use the register_type convenience function, defined
+  // below.
+  bool register_type(TypeHandle &type_handle, const string &name);
+  TypeHandle register_dynamic_type(const string &name);
+
+  void record_derivation(TypeHandle child, TypeHandle parent);
+  void record_alternate_name(TypeHandle type, const string &name);
+
+PUBLISHED:
+  TypeHandle find_type(const string &name) const;
+
+  string get_name(TypeHandle type, TypedObject *object) const;
+  INLINE bool is_derived_from(TypeHandle child, TypeHandle base,
+                              TypedObject *child_object);
+
+  int get_num_root_classes();
+  TypeHandle get_root_class(int n);
+
+  int get_num_parent_classes(TypeHandle child,
+                             TypedObject *child_object) const;
+  TypeHandle get_parent_class(TypeHandle child, int index) const;
+
+  int get_num_child_classes(TypeHandle child,
+                            TypedObject *child_object) const;
+  TypeHandle get_child_class(TypeHandle child, int index) const;
+
+  TypeHandle get_parent_towards(TypeHandle child, TypeHandle base,
+                                TypedObject *child_object) const;
+
+  static void reregister_types();
+
+  void write(ostream &out) const;
+
+  // ptr() returns the pointer to the global TypeRegistry object.
+  static TypeRegistry *ptr();
+
+private:
+  // The TypeRegistry class should never be constructed by user code.
+  // There is only one in the universe, and it constructs itself!
+  TypeRegistry();
+
+  static void init_global_pointer();
+
+  // In NDEBUG mode, this is an inline function; otherwise, it's
+  // out-of-line.
+#ifdef NDEBUG
+  INLINE TypeRegistryNode *look_up(TypeHandle type, TypedObject *object) const;
+#else
+  TypeRegistryNode *look_up(TypeHandle type, TypedObject *object) const;
+#endif
+
+  INLINE void freshen_derivations();
+  void rebuild_derivations();
+  void write_node(ostream &out, int indent_level,
+                  const TypeRegistryNode *node) const;
+
+  typedef pvector<TypeRegistryNode *> HandleRegistry;
+  HandleRegistry _handle_registry;
+
+  typedef pmap<string, TypeRegistryNode *> NameRegistry;
+  NameRegistry _name_registry;
+
+  typedef pvector<TypeRegistryNode *> RootClasses;
+  RootClasses _root_classes;
+
+  bool _derivations_fresh;
+
+  static TypeRegistry *_global_pointer;
+};
+
+#include "typeRegistry.I"
+
+#endif

+ 104 - 0
panda/src/express/typeRegistryNode.I

@@ -0,0 +1,104 @@
+// Filename: typeRegistryNode.I
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::Inherit::Default Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE TypeRegistryNode::Inherit::
+Inherit() {
+  _top = (TypeRegistryNode *)NULL;
+  _mask = 0;
+  _bits = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::Inherit::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE TypeRegistryNode::Inherit::
+Inherit(TypeRegistryNode *top, int bit_count,
+        TypeRegistryNode::SubtreeMaskType bits) {
+  nassertv(bit_count < (int)(sizeof(SubtreeMaskType) * 8));
+  _top = top;
+
+  // Build a bitmask consisting of bit_count low-order bits.
+  _mask = ((SubtreeMaskType)1 << bit_count) - 1;
+
+  // There shouldn't be anything but zeroes after bit_count bits.
+  nassertv((bits & ~_mask) == 0);
+  _bits = bits;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::Inherit::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE TypeRegistryNode::Inherit::
+Inherit(const TypeRegistryNode::Inherit &copy) :
+  _top(copy._top),
+  _mask(copy._mask),
+  _bits(copy._bits)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::Inherit::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void TypeRegistryNode::Inherit::
+operator = (const TypeRegistryNode::Inherit &copy) {
+  _top = copy._top;
+  _mask = copy._mask;
+  _bits = copy._bits;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::Inherit::Ordering operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool TypeRegistryNode::Inherit::
+operator < (const Inherit &other) const {
+  return _top < other._top;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::Inherit::is_derived_from
+//       Access: Public
+//  Description: Assuming the two Inherit objects share the same
+//               subtree top, this returns true if the bitmasks
+//               indicate that child inherits from base, or false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool TypeRegistryNode::Inherit::
+is_derived_from(const TypeRegistryNode::Inherit &child, 
+                const TypeRegistryNode::Inherit &base) {
+  nassertr(child._top == base._top, false);
+
+  // Child derives from base if and only if its subtree mask contains
+  // more bits (or the same number of bits), and the n low-order
+  // subtree bits that are in common are identical.
+  return ((child._mask & base._mask) == base._mask &&
+          (child._bits & base._mask) == base._bits);
+}

+ 377 - 0
panda/src/express/typeRegistryNode.cxx

@@ -0,0 +1,377 @@
+// Filename: typeRegistryNode.cxx
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "typeRegistryNode.h"
+
+#include <algorithm>
+
+// Define this to double-check all the inheritance derivations.
+//#define PARANOID_INHERITANCE
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+TypeRegistryNode::
+TypeRegistryNode(TypeHandle handle, const string &name, TypeHandle &ref) :
+  _handle(handle), _name(name), _ref(ref) 
+{
+  clear_subtree();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::is_derived_from
+//       Access: Public, Static
+//  Description: Returns true if the child RegistryNode represents a
+//               class that inherits directly or indirectly from the
+//               class represented by the base RegistryNode.
+////////////////////////////////////////////////////////////////////
+bool TypeRegistryNode::
+is_derived_from(const TypeRegistryNode *child, const TypeRegistryNode *base) {
+  // This function is the basis for TypedObject::is_of_type(), which
+  // gets used quite frequently within Panda, often in inner-loop
+  // code.  Therefore, we go through some pains to make this function
+  // as efficient as possible.
+
+  // First, compare the subtree tops.  If they are the same, then this
+  // node and the base node are within the same single-inheritance
+  // subtree, and we can use our bitmask trick to determine the
+  // relationship with no additional work.  (See r_build_subtrees()).
+
+  if (child->_inherit._top == base->_inherit._top) {
+    nassertr(child->_inherit._top != (TypeRegistryNode *)NULL, false);
+
+    bool derives = 
+      Inherit::is_derived_from(child->_inherit, base->_inherit);
+
+#ifdef PARANOID_INHERITANCE
+    bool paranoid_derives = check_derived_from(child, base);
+    if (derives != paranoid_derives) {
+      express_cat.error()
+        << "Inheritance test for " << child->_name 
+        << " from " << base->_name << " failed!\n"
+        << "Result: " << derives << " should have been: "
+        << paranoid_derives << "\n"
+        << "Classes are in the same single inheritance subtree, children of "
+        << child->_inherit._top->_name << "\n"
+        << hex
+        << child->_name << " has mask " << child->_inherit._mask
+        << " and bits " << child->_inherit._bits << "\n"
+        << base->_name << " has mask " << base->_inherit._mask
+        << " and bits " << base->_inherit._bits << "\n"
+        << dec;
+      return paranoid_derives;
+    }
+#endif
+
+    /*
+    cerr << "trivial: " << child->_name << " vs. " << base->_name
+         << " (" << child->_inherit._top->_name << ") = " << derives << "\n";
+    */
+
+    return derives;
+  }
+
+  // The two nodes are not within the same single-inheritance subtree.
+  // This complicates things a bit.
+
+  // First, we should check whether the subtree tops of the two nodes
+  // inherit from each other.
+  const TypeRegistryNode *child_top = child->_inherit._top;
+  const TypeRegistryNode *base_top = base->_inherit._top;
+
+  bool derives = false;
+
+  // If child_top does not inherit from base_top, it follows that
+  // child does not inherit from base.
+  TopInheritance::const_iterator ti = child_top->find_top_inherit(base_top);
+
+  while (ti != child_top->_top_inheritance.end() && 
+         (*ti)._top == base_top &&
+         !derives) {
+    // If child_top *does* inherit from base_top, then child may or
+    // may not inherit from base.  This depends on the exact path of
+    // inheritance.  Since there might be multiple paths from
+    // child_top to base_top, we have to examine all of them.
+    const Inherit &connection = (*ti);
+
+    // Here is one inheritance from child_top to base_top.  If the
+    // connecting node inherits from base, then child also inherits
+    // from base.  If the connecting node does not inherit from base,
+    // we must keep looking.
+    derives = Inherit::is_derived_from(connection, base->_inherit);
+
+    ++ti;
+  }
+
+#ifdef PARANOID_INHERITANCE
+  bool paranoid_derives = check_derived_from(child, base);
+  if (derives != paranoid_derives) {
+    express_cat.error()
+      << "Inheritance test for " << child->_name 
+      << " from " << base->_name << " failed!\n"
+      << "Result: " << derives << " should have been: "
+      << paranoid_derives << "\n"
+      << child->_name << " is a descendent of "
+      << child_top->_name << "\n"
+      << base->_name << " is a descendent of "
+      << base_top->_name << "\n";
+    return paranoid_derives;
+  }
+#endif
+
+  /*
+  cerr << "complex: " << child->_name << " (" << child->_inherit._top->_name
+       << ") vs. " << base->_name << " (" << base->_inherit._top->_name
+       << ") = " << derives << "\n";
+  */
+  return derives;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::get_parent_towards
+//       Access: Public, Static
+//  Description: Returns the first parent class of child that is a
+//               descendant of the indicated base class.
+////////////////////////////////////////////////////////////////////
+TypeHandle TypeRegistryNode::
+get_parent_towards(const TypeRegistryNode *child,
+                   const TypeRegistryNode *base) {
+  if (child == base) {
+    return child->_handle;
+  }
+
+  Classes::const_iterator ni;
+  for (ni = child->_parent_classes.begin(); 
+       ni != child->_parent_classes.end(); ++ni) {
+    if (is_derived_from((*ni), base)) {
+      return (*ni)->_handle;
+    }
+  }
+
+  return TypeHandle::none();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::clear_subtree
+//       Access: Public
+//  Description: Removes any subtree definition previously set up via
+//               define_subtree(), in preparation for rebuilding the
+//               subtree data.
+////////////////////////////////////////////////////////////////////
+void TypeRegistryNode::
+clear_subtree() {
+  _inherit = Inherit();
+  _top_inheritance.clear();
+  _visit_count = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::define_subtree
+//       Access: Public
+//  Description: Indicates that this TypeRegistryNode is the top of a
+//               subtree within the inheritance graph (typically, this
+//               indicates a multiple-inheritance node).  Builds all
+//               the subtree_mask etc. flags for nodes at this level
+//               and below.
+////////////////////////////////////////////////////////////////////
+void TypeRegistryNode::
+define_subtree() {
+  //  cerr << "Building subtree for " << _name << ", top inheritance is:\n";
+
+    /*
+  TopInheritance::const_iterator ti;
+  for (ti = _top_inheritance.begin(); ti != _top_inheritance.end(); ++ti) {
+    const Inherit &t = (*ti);
+    cerr << "  from " << t._top->_name << " via "
+         << hex << t._bits << " / " << t._mask << dec << "\n";
+  }
+    */
+
+  r_build_subtrees(this, 0, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::r_build_subtrees
+//       Access: Public
+//  Description: Recursively builds up all the subtree cache
+//               information for this node and the ones below.  This
+//               information is used to quickly determine class
+//               inheritance.
+////////////////////////////////////////////////////////////////////
+void TypeRegistryNode::
+r_build_subtrees(TypeRegistryNode *top, int bit_count, 
+                 TypeRegistryNode::SubtreeMaskType bits) {
+  // The idea with these bits is to optimize the common case of a
+  // single-inheritance graph (that is, an inheritance tree), or a
+  // single-inheritance subgraph of the full multiple-inheritance
+  // graph (i.e. a subtree of the inheritance graph).
+
+  // When we have just single inheritance, we can define a unique
+  // number for each node in the inheritance tree that allows us to
+  // immediately determine the inheritance relationship between any
+  // two nodes in the tree.  We choose a number such that for a given
+  // node whose number has n bits, each child node has m + n bits
+  // where the low-order n bits are the same as the parent node's
+  // bits, and the high-order m bits are unique among each sibling.
+  // The node at the top of the tree has zero bits.
+
+  // That way, we can simply compare bitmasks to determine if class A
+  // inherits from class B.  If the low-order bits are the same, they
+  // have some ancestry in common.  The highest-order bit that still
+  // matches corresponds to the lowest node in the tree that they have
+  // in common; i.e. the node from which they both inherit.
+
+  // To put it more formally, let count(A) be the number of bits in
+  // A's number, and count(B) be the number of bits in B's number.  A
+  // inherits from B if and only if count(B) <= count(A), and the
+  // lower count(B) bits of A's number are the same as those in B's
+  // number.
+
+  // This algorithm breaks down in the presence of multiple
+  // inheritance, since we can't make up a single number for each node
+  // any more.  We still take advantage of the algorithm by
+  // considering each single-inheritance subgraph separately.
+
+  // To handle multiple inheritance, we reset the numbers to zero
+  // every time we come across a multiple-inheritance node (this
+  // begins a new subtree).  There are relatively few of these
+  // "subtree top" nodes, and we record the explicit inheritance of
+  // each one from all of its ancestor "subtree top" nodes within the
+  // node itself.
+
+  if (top != this && _parent_classes.size() != 1) {
+    nassertv(!_parent_classes.empty());
+  
+    // This class multiply inherits; it therefore begins a new subtree.
+
+    // Copy in the inheritance relations from our parent subtree tops.
+    _top_inheritance.insert(_top_inheritance.end(),
+                            top->_top_inheritance.begin(), 
+                            top->_top_inheritance.end());
+    _top_inheritance.push_back(Inherit(top, bit_count, bits));
+
+    _visit_count++;
+    if (_visit_count == (int)_parent_classes.size()) {
+      // This is the last time we'll visit this node, so continue the
+      // recursion now.
+      nassertv(_inherit._top == (TypeRegistryNode *)NULL);
+      sort(_top_inheritance.begin(), _top_inheritance.end());
+      define_subtree();
+    }
+
+  } else {
+    // This class singly inherits, so this had better be the only time
+    // this function is called on it since clear_subtree().
+    nassertv(_inherit._top == (TypeRegistryNode *)NULL);
+
+    nassertv(bit_count < (int)(sizeof(SubtreeMaskType) * 8));
+
+    _inherit = Inherit(top, bit_count, bits);
+
+    // Now, how many more bits do we need to encode each of our
+    // children?
+    int num_children = _child_classes.size();
+    int more_bits = 0;
+    int i = num_children - 1;
+    while (i > 0) {
+      more_bits++;
+      i >>= 1;
+    }
+
+    // We need at least one bit, even if there is only one child, so
+    // we can differentiate parent from child.
+    more_bits = max(more_bits, 1);
+
+    nassertv(more_bits < (int)(sizeof(SubtreeMaskType) * 8));
+
+    if (bit_count + more_bits > (int)(sizeof(SubtreeMaskType) * 8)) {
+      // Too many bits; we need to start a new subtree right here.
+      // This node becomes a subtree top node, even though it's not a
+      // multiple-inheritance node.
+      nassertv(top != this);
+      _top_inheritance = top->_top_inheritance;
+      _top_inheritance.push_back(_inherit);
+      sort(_top_inheritance.begin(), _top_inheritance.end());
+      _inherit = Inherit();
+      define_subtree();
+
+    } else {
+      // Still plenty of bits, so keep going.
+      for (i = 0; i < num_children; i++) {
+        TypeRegistryNode *child = _child_classes[i];
+        SubtreeMaskType next_bits = ((SubtreeMaskType)i << bit_count);
+
+        child->r_build_subtrees(top, bit_count + more_bits,
+                                bits | next_bits);
+      }
+    }      
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::find_top_inherit
+//       Access: Private, Static
+//  Description: Finds the first element in the _top_inheritance array
+//               that matches the indicated base node.  If the base
+//               node does not appear in the _top_inheritance array
+//               (implying that this node does not inherit from the
+//               base node), returns _top_inheritance.end().
+////////////////////////////////////////////////////////////////////
+TypeRegistryNode::TopInheritance::const_iterator TypeRegistryNode::
+find_top_inherit(const TypeRegistryNode *base) const {
+  TopInheritance::const_iterator ti;
+  for (ti = _top_inheritance.begin(); ti != _top_inheritance.end(); ++ti) {
+    if ((*ti)._top == base) {
+      return ti;
+    }
+  }
+
+  return _top_inheritance.end();
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: TypeRegistryNode::check_derived_from
+//       Access: Private, Static
+//  Description: A recursive function to double-check the result of
+//               is_derived_from().  This is the slow,
+//               examine-the-whole-graph approach, as opposed to the
+//               clever and optimal algorithm of is_derived_from();
+//               it's intended to be used only for debugging said
+//               clever algorithm.
+////////////////////////////////////////////////////////////////////
+bool TypeRegistryNode::
+check_derived_from(const TypeRegistryNode *child, 
+                   const TypeRegistryNode *base) {
+  if (child == base) {
+    return true;
+  }
+
+  Classes::const_iterator ni;
+  for (ni = child->_parent_classes.begin(); 
+       ni != child->_parent_classes.end();
+       ++ni) {
+    if (check_derived_from(*ni, base)) {
+      return true;
+    }
+  }
+
+  return false;
+}

+ 101 - 0
panda/src/express/typeRegistryNode.h

@@ -0,0 +1,101 @@
+// Filename: typeRegistryNode.h
+// Created by:  drose (06Aug01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef TYPEREGISTRYNODE_H
+#define TYPEREGISTRYNODE_H
+
+#include "pandabase.h"
+
+#include "typeHandle.h"
+
+#include "pvector.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : TypeRegistryNode
+// Description : This is a single entry in the TypeRegistry.
+//               Normally, user code will never directly access this
+//               class; this class is hidden within the TypeRegistry
+//               accessors.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS TypeRegistryNode {
+public:
+  TypeRegistryNode(TypeHandle handle, const string &name, TypeHandle &ref);
+
+  static bool is_derived_from(const TypeRegistryNode *child,
+                              const TypeRegistryNode *base);
+
+  static TypeHandle get_parent_towards(const TypeRegistryNode *child,
+                                       const TypeRegistryNode *base);
+
+  void clear_subtree();
+  void define_subtree();
+
+  TypeHandle _handle;
+  string _name;
+  TypeHandle &_ref;
+  typedef pvector<TypeRegistryNode *> Classes;
+  Classes _parent_classes;
+  Classes _child_classes;
+
+private:
+  typedef int SubtreeMaskType;
+
+  // This class defines the inheritance relationship of this node from
+  // some ancestor denoted as a "subtree top" node.  This is usually
+  // the nearest ancestor that has multiple inheritance.
+  class Inherit {
+  public:
+    INLINE Inherit();
+    INLINE Inherit(TypeRegistryNode *top, int bit_count, 
+                   SubtreeMaskType bits);
+    INLINE Inherit(const Inherit &copy);
+    INLINE void operator = (const Inherit &copy);
+    
+    INLINE bool operator < (const Inherit &other) const;
+    INLINE static bool is_derived_from(const Inherit &child, const Inherit &base);
+
+    TypeRegistryNode *_top;
+    SubtreeMaskType _mask;
+    SubtreeMaskType _bits;
+  };
+  typedef pvector<Inherit> TopInheritance;
+
+  void r_build_subtrees(TypeRegistryNode *top, 
+                        int bit_count, SubtreeMaskType bits);
+
+  TopInheritance::const_iterator
+  find_top_inherit(const TypeRegistryNode *base) const;
+
+  static bool check_derived_from(const TypeRegistryNode *child,
+                                 const TypeRegistryNode *base);
+
+  Inherit _inherit;
+
+  // The _top_inheritance member is only filled for nodes that are
+  // denoted as "subtree top" nodes.  It represents the complete set
+  // of subtree_top nodes that this node inherits from, directly or
+  // indirectly.
+  TopInheritance _top_inheritance;
+
+  // _visit_count is only used during r_build_subtree().
+  int _visit_count;
+};
+
+#include "typeRegistryNode.I"
+
+#endif

+ 2 - 58
panda/src/express/typedObject.h

@@ -19,9 +19,10 @@
 #ifndef TYPEDOBJECT_H
 #define TYPEDOBJECT_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "typeHandle.h"
+#include "register_type.h"
 
 
 ////////////////////////////////////////////////////////////////////
@@ -70,63 +71,6 @@ private:
   static TypeHandle _type_handle;
 };
 
-// The DCAST (downcast) macro is defined as a convenience for
-// downcasting from some TypedObject pointer (or a PointerTo).  It's
-// just a normal C++-style downcast, except it first checks get_type()
-// to make sure the downcasting is safe.  If you compile with NDEBUG,
-// this check is removed.
-
-// DCAST will return NULL if the downcasting is unsafe.  If you'd
-// rather it abort out of the function (ala nassertv/nassertr), then
-// see DCAST_INTO_V and DCAST_INTO_R, below.
-
-template<class WantType>
-INLINE WantType *_dcast(WantType *, TypedObject *ptr);
-template<class WantType>
-INLINE const WantType *_dcast(WantType *, const TypedObject *ptr);
-
-// Note: it is important that DCAST not repeat the pointer parameter,
-// since many users of DCAST may want to use the result of a function
-// as the pointer parameter, and it could be terribly confusing and
-// difficult to trace if the function was executed twice.  This
-// happened!
-#define DCAST(want_type, pointer) _dcast((want_type*)0, pointer)
-
-// DCAST_INTO_V and DCAST_INTO_R are similar in purpose to DCAST,
-// except they: (a) automatically assign a variable instead of
-// returning the downcasted pointer, and (b) they immediately return
-// out of the function if the downcasting fails.  DCAST_INTO_V is for
-// use in a void function and returns nothing; DCAST_INTO_R is for use
-// in a non-void function and returns the indicated value.
-
-// Both DCAST_INTO_V and DCAST_INTO_R accept as the first parameter a
-// variable of type (want_type *) or (const want_type *), instead of
-// the name of the type.  This variable will be filled with the new
-// pointer.
-
-
-// _dcast_ref is used to implement DCAST_INTO_V and DCAST_INTO_R.  Its
-// difference from _dcast is that it takes a reference to a pointer as
-// a first parameter.  The main point of this is to shut up the
-// compiler about pointers used before their value is assigned.
-template<class WantType>
-INLINE WantType *_dcast_ref(WantType *&, TypedObject *ptr);
-template<class WantType>
-INLINE const WantType *_dcast_ref(WantType *&, const TypedObject *ptr);
-
-
-#define DCAST_INTO_V(to_pointer, from_pointer) \
-  { \
-    (to_pointer) = _dcast_ref(to_pointer, from_pointer); \
-    nassertv((void *)(to_pointer) != (void *)NULL); \
-  }
-
-#define DCAST_INTO_R(to_pointer, from_pointer, return_value) \
-  { \
-    (to_pointer) = _dcast_ref(to_pointer, from_pointer); \
-    nassertr((void *)(to_pointer) != (void *)NULL, return_value); \
-  }
-
 #include "typedObject.I"
 
 #endif

+ 48 - 47
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -22,54 +22,55 @@
 #include "glGeomNodeContext.h"
 #include "config_glgsg.h"
 
-#include <config_util.h>
-#include <directRenderTraverser.h>
-#include <cullTraverser.h>
-#include <displayRegion.h>
-#include <projectionNode.h>
-#include <camera.h>
-#include <renderBuffer.h>
-#include <geom.h>
-#include <geomIssuer.h>
-#include <graphicsWindow.h>
-#include <graphicsChannel.h>
-#include <projection.h>
-#include <get_rel_pos.h>
-#include <perspectiveProjection.h>
-#include <ambientLight.h>
-#include <directionalLight.h>
-#include <pointLight.h>
-#include <spotlight.h>
-#include <GL/glu.h>
-#include <projectionNode.h>
-#include <transformTransition.h>
-#include <colorMatrixTransition.h>
-#include <alphaTransformTransition.h>
-#include <colorTransition.h>
-#include <lightTransition.h>
-#include <textureTransition.h>
-#include <renderModeTransition.h>
-#include <materialTransition.h>
-#include <colorBlendTransition.h>
-#include <colorMaskTransition.h>
-#include <texMatrixTransition.h>
-#include <texGenTransition.h>
-#include <textureApplyTransition.h>
-#include <clipPlaneTransition.h>
-#include <transparencyTransition.h>
-#include <fogTransition.h>
-#include <linesmoothTransition.h>
-#include <depthTestTransition.h>
-#include <depthWriteTransition.h>
-#include <cullFaceTransition.h>
-#include <stencilTransition.h>
-#include <pointShapeTransition.h>
-#include <polygonOffsetTransition.h>
-#include <clockObject.h>
-#include <pStatTimer.h>
-#include <string_utils.h>
-
+#include "config_util.h"
+#include "directRenderTraverser.h"
+#include "cullTraverser.h"
+#include "displayRegion.h"
+#include "projectionNode.h"
+#include "camera.h"
+#include "renderBuffer.h"
+#include "geom.h"
+#include "geomIssuer.h"
+#include "graphicsWindow.h"
+#include "graphicsChannel.h"
+#include "projection.h"
+#include "get_rel_pos.h"
+#include "perspectiveProjection.h"
+#include "ambientLight.h"
+#include "directionalLight.h"
+#include "pointLight.h"
+#include "spotlight.h"
+#include "GL/glu.h"
+#include "projectionNode.h"
+#include "transformTransition.h"
+#include "colorMatrixTransition.h"
+#include "alphaTransformTransition.h"
+#include "colorTransition.h"
+#include "lightTransition.h"
+#include "textureTransition.h"
+#include "renderModeTransition.h"
+#include "materialTransition.h"
+#include "colorBlendTransition.h"
+#include "colorMaskTransition.h"
+#include "texMatrixTransition.h"
+#include "texGenTransition.h"
+#include "textureApplyTransition.h"
+#include "clipPlaneTransition.h"
+#include "transparencyTransition.h"
+#include "fogTransition.h"
+#include "linesmoothTransition.h"
+#include "depthTestTransition.h"
+#include "depthWriteTransition.h"
+#include "cullFaceTransition.h"
+#include "stencilTransition.h"
+#include "pointShapeTransition.h"
+#include "polygonOffsetTransition.h"
+#include "clockObject.h"
+#include "pStatTimer.h"
+#include "string_utils.h"
+#include "dcast.h"
 #include "pvector.h"
+
 #include <algorithm>
 
 #if 0

+ 3 - 2
panda/src/graph/nodeTransition.h

@@ -19,11 +19,12 @@
 #ifndef NODETRANSITION_H
 #define NODETRANSITION_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "graphHashGenerator.h"
 
-#include <typedWritableReferenceCount.h>
+#include "pset.h"
+#include "typedWritableReferenceCount.h"
 
 class Node;
 class NodeTransitions;

+ 3 - 2
panda/src/graph/nodeTransitions.h

@@ -19,11 +19,12 @@
 #ifndef NODETRANSITIONS_H
 #define NODETRANSITIONS_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "nodeTransition.h"
 
-#include <pointerTo.h>
+#include "pointerTo.h"
+#include "dcast.h"
 
 #include "pmap.h"
 

+ 3 - 3
panda/src/graph/nullLevelState.h

@@ -29,9 +29,9 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA NullLevelState {
 public:
-  INLINE_GRAPH NullLevelState() { }
-  INLINE_GRAPH NullLevelState(const NullLevelState &) { }
-  INLINE_GRAPH void operator = (const NullLevelState &) { }
+  INLINE NullLevelState() { }
+  INLINE NullLevelState(const NullLevelState &) { }
+  INLINE void operator = (const NullLevelState &) { }
 };
 
 #endif

+ 20 - 20
panda/src/graph/nullTransitionWrapper.I

@@ -24,7 +24,7 @@
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH NullTransitionWrapper::
+INLINE NullTransitionWrapper::
 NullTransitionWrapper() {
 }
 
@@ -33,7 +33,7 @@ NullTransitionWrapper() {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH NullTransitionWrapper::
+INLINE NullTransitionWrapper::
 NullTransitionWrapper(const NullTransitionWrapper &) {
 }
 
@@ -42,7 +42,7 @@ NullTransitionWrapper(const NullTransitionWrapper &) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 operator = (const NullTransitionWrapper &) {
 }
 
@@ -51,7 +51,7 @@ operator = (const NullTransitionWrapper &) {
 //       Access: Public, Static
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH NullTransitionWrapper NullTransitionWrapper::
+INLINE NullTransitionWrapper NullTransitionWrapper::
 init_from(const NullTransitionWrapper &) {
   return NullTransitionWrapper();
 }
@@ -61,7 +61,7 @@ init_from(const NullTransitionWrapper &) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH bool NullTransitionWrapper::
+INLINE bool NullTransitionWrapper::
 is_identity() const {
   return true;
 }
@@ -71,7 +71,7 @@ is_identity() const {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH int NullTransitionWrapper::
+INLINE int NullTransitionWrapper::
 compare_to(const NullTransitionWrapper &) const {
   return 0;
 }
@@ -81,7 +81,7 @@ compare_to(const NullTransitionWrapper &) const {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 make_identity() {
 }
 
@@ -90,7 +90,7 @@ make_identity() {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 extract_from(const NodeRelation *) {
 }
 
@@ -99,7 +99,7 @@ extract_from(const NodeRelation *) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 store_to(NodeRelation *) const {
 }
 
@@ -108,7 +108,7 @@ store_to(NodeRelation *) const {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 compose_in_place(const NullTransitionWrapper &) {
 }
 
@@ -117,7 +117,7 @@ compose_in_place(const NullTransitionWrapper &) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 invert_in_place() {
 }
 
@@ -126,7 +126,7 @@ invert_in_place() {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 invert_compose_in_place(const NullTransitionWrapper &) {
 }
 
@@ -135,7 +135,7 @@ invert_compose_in_place(const NullTransitionWrapper &) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH Node *NullTransitionWrapper::
+INLINE Node *NullTransitionWrapper::
 extract_from_cache(const NodeRelation *) {
   return NULL;
 }
@@ -146,7 +146,7 @@ extract_from_cache(const NodeRelation *) {
 //  Description: Stores this transition into the arc's cache, and
 //               updates the arc's top_subtree.
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 store_to_cache(NodeRelation *, Node *) {
 }
 
@@ -155,7 +155,7 @@ store_to_cache(NodeRelation *, Node *) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH bool NullTransitionWrapper::
+INLINE bool NullTransitionWrapper::
 is_cache_verified(UpdateSeq) const {
   return true;
 }
@@ -165,7 +165,7 @@ is_cache_verified(UpdateSeq) const {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 set_computed_verified(UpdateSeq) {
 }
 
@@ -176,7 +176,7 @@ set_computed_verified(UpdateSeq) {
 //               that indicated by value, using the cache as a helper,
 //               and stores the result in this wrapper.
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 cached_compose(const NullTransitionWrapper &,
                const NullTransitionWrapper &,
                UpdateSeq) {
@@ -187,7 +187,7 @@ cached_compose(const NullTransitionWrapper &,
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 output(ostream &) const {
 }
 
@@ -196,11 +196,11 @@ output(ostream &) const {
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE_GRAPH void NullTransitionWrapper::
+INLINE void NullTransitionWrapper::
 write(ostream &, int) const {
 }
 
-INLINE_GRAPH ostream &operator << (ostream &out, const NullTransitionWrapper &ntw) {
+INLINE ostream &operator << (ostream &out, const NullTransitionWrapper &ntw) {
   ntw.output(out);
   return out;
 }

+ 26 - 22
panda/src/graph/nullTransitionWrapper.h

@@ -46,47 +46,51 @@ class NodeRelation;
 //               wrt(), but it's useful for passing to df_traverse()
 //               to perform a traversal without bothering to keep
 //               track of state.
+
+//               It is important that these functions be honestly
+//               flagged INLINE, instead of INLINE_GRAPH, so that they
+//               honestly get flagged as inline functions, so they can
+//               be optimized away by the compiler.  They don't hide
+//               anything that can't be exported anyway.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA NullTransitionWrapper {
 public:
   typedef NullTransitionWrapper TransitionWrapper;
 
-  INLINE_GRAPH NullTransitionWrapper();
-  INLINE_GRAPH NullTransitionWrapper(const NullTransitionWrapper &copy);
-  INLINE_GRAPH void operator = (const NullTransitionWrapper &copy);
+  INLINE NullTransitionWrapper();
+  INLINE NullTransitionWrapper(const NullTransitionWrapper &copy);
+  INLINE void operator = (const NullTransitionWrapper &copy);
 
-  INLINE_GRAPH static NullTransitionWrapper
+  INLINE static NullTransitionWrapper
   init_from(const NullTransitionWrapper &other);
 
-  INLINE_GRAPH bool is_identity() const;
-  INLINE_GRAPH int compare_to(const NullTransitionWrapper &other) const;
+  INLINE bool is_identity() const;
+  INLINE int compare_to(const NullTransitionWrapper &other) const;
 
-  INLINE_GRAPH void make_identity();
-  INLINE_GRAPH void extract_from(const NodeRelation *arc);
-  INLINE_GRAPH void store_to(NodeRelation *arc) const;
+  INLINE void make_identity();
+  INLINE void extract_from(const NodeRelation *arc);
+  INLINE void store_to(NodeRelation *arc) const;
 
-  INLINE_GRAPH void compose_in_place(const NullTransitionWrapper &other);
-  INLINE_GRAPH void invert_in_place();
-  INLINE_GRAPH void invert_compose_in_place(const NullTransitionWrapper &other);
+  INLINE void compose_in_place(const NullTransitionWrapper &other);
+  INLINE void invert_in_place();
+  INLINE void invert_compose_in_place(const NullTransitionWrapper &other);
 
-  INLINE_GRAPH Node *extract_from_cache(const NodeRelation *arc);
-  INLINE_GRAPH void store_to_cache(NodeRelation *arc, Node *top_subtree);
-  INLINE_GRAPH bool is_cache_verified(UpdateSeq now) const;
-  INLINE_GRAPH void set_computed_verified(UpdateSeq now);
+  INLINE Node *extract_from_cache(const NodeRelation *arc);
+  INLINE void store_to_cache(NodeRelation *arc, Node *top_subtree);
+  INLINE bool is_cache_verified(UpdateSeq now) const;
+  INLINE void set_computed_verified(UpdateSeq now);
 
-  INLINE_GRAPH void cached_compose(const NullTransitionWrapper &cache,
+  INLINE void cached_compose(const NullTransitionWrapper &cache,
                              const NullTransitionWrapper &value,
                              UpdateSeq now);
 
-  INLINE_GRAPH void output(ostream &out) const;
-  INLINE_GRAPH void write(ostream &out, int indent_level = 0) const;
+  INLINE void output(ostream &out) const;
+  INLINE void write(ostream &out, int indent_level = 0) const;
 };
 
-INLINE_GRAPH ostream &operator << (ostream &out, const NullTransitionWrapper &ntw);
+INLINE ostream &operator << (ostream &out, const NullTransitionWrapper &ntw);
 
-#ifndef DONT_INLINE_GRAPH
 #include "nullTransitionWrapper.I"
-#endif
 
 #endif
 

+ 1 - 0
panda/src/mathutil/boundingSphere.cxx

@@ -20,6 +20,7 @@
 #include "boundingHexahedron.h"
 #include "boundingLine.h"
 #include "config_mathutil.h"
+#include "dcast.h"
 
 #include <math.h>
 #include <algorithm>

+ 3 - 2
panda/src/pnmimage/pnmFileTypeRegistry.cxx

@@ -20,8 +20,9 @@
 #include "pnmFileType.h"
 #include "config_pnmimage.h"
 
-#include <string_utils.h>
-#include <indent.h>
+#include "string_utils.h"
+#include "indent.h"
+#include "pset.h"
 
 #include <algorithm>
 

+ 0 - 10
panda/src/putil/Sources.pp

@@ -134,13 +134,3 @@
     test_linestream.cxx
 
 #end test_bin_target
-
-#begin test_bin_target
-  #define TARGET test_types
-  #define LOCAL_LIBS $[LOCAL_LIBS] putil
-
-  #define SOURCES \
-    test_types.cxx
-
-#end test_bin_target
-

+ 2 - 0
panda/src/putil/bamReader.h

@@ -28,6 +28,8 @@
 #include "bamReaderParam.h"
 #include "factory.h"
 #include "vector_ushort.h"
+#include "pset.h"
+#include "dcast.h"
 
 #include <algorithm>
 

+ 1 - 0
panda/src/sgattrib/alphaTransformTransition.cxx

@@ -20,6 +20,7 @@
 
 #include "graphicsStateGuardianBase.h"
 #include "indent.h"
+#include "dcast.h"
 
 TypeHandle AlphaTransformTransition::_type_handle;
 

+ 2 - 1
panda/src/sgattrib/fogTransition.cxx

@@ -18,7 +18,8 @@
 
 #include "fogTransition.h"
 
-#include <indent.h>
+#include "dcast.h"
+#include "indent.h"
 
 TypeHandle FogTransition::_type_handle;
 

+ 2 - 2
panda/src/sgraphutil/quickRenderTraverser.cxx

@@ -170,8 +170,8 @@ forward_arc(NodeRelation *arc, NullTransitionWrapper &,
       */
     }
 
-    AllTransitionsWrapper attrib(_initial_state);
-    attrib.compose_in_place(trans);
+    AllTransitionsWrapper attrib;
+    attrib.compose_from(_initial_state, trans);
 
     _gsg->set_state(attrib.get_transitions(), true);
     gnode->draw(_gsg);

+ 3 - 2
panda/src/vrpn/vrpnClient.cxx

@@ -27,8 +27,9 @@
 #include "vrpnDialDevice.h"
 #include "config_vrpn.h"
 
-#include <string_utils.h>
-#include <indent.h>
+#include "dcast.h"
+#include "string_utils.h"
+#include "indent.h"
 
 TypeHandle VrpnClient::_type_handle;