From 764aea593ef9be95d91d163c30e16df62a9b1387 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 7 Aug 2001 02:00:46 +0000 Subject: [PATCH] optimize is_of_type(), in theory --- .../src/dgraph/buttonEventDataTransition.cxx | 1 + panda/src/egg/eggBinMaker.cxx | 3 +- panda/src/egg/eggPolysetMaker.h | 4 +- panda/src/egg/parser.yxx | 12 +- panda/src/express/Sources.pp | 28 +- panda/src/express/dcast.T | 127 ++++ panda/src/express/dcast.h | 90 +++ panda/src/express/express_composite2.cxx | 3 + panda/src/express/register_type.I | 120 +++ panda/src/express/register_type.cxx | 61 ++ panda/src/express/register_type.h | 285 ++++++++ panda/src/{putil => express}/test_types.cxx | 1 + panda/src/express/typeHandle.I | 217 ------ panda/src/express/typeHandle.cxx | 681 ------------------ panda/src/express/typeHandle.h | 361 +--------- panda/src/express/typeRegistry.I | 79 ++ panda/src/express/typeRegistry.cxx | 608 ++++++++++++++++ panda/src/express/typeRegistry.h | 116 +++ panda/src/express/typeRegistryNode.I | 104 +++ panda/src/express/typeRegistryNode.cxx | 377 ++++++++++ panda/src/express/typeRegistryNode.h | 101 +++ panda/src/express/typedObject.h | 60 +- panda/src/glgsg/glGraphicsStateGuardian.cxx | 95 +-- panda/src/graph/nodeTransition.h | 5 +- panda/src/graph/nodeTransitions.h | 5 +- panda/src/graph/nullLevelState.h | 6 +- panda/src/graph/nullTransitionWrapper.I | 40 +- panda/src/graph/nullTransitionWrapper.h | 48 +- panda/src/mathutil/boundingSphere.cxx | 1 + panda/src/pnmimage/pnmFileTypeRegistry.cxx | 5 +- panda/src/putil/Sources.pp | 10 - panda/src/putil/bamReader.h | 2 + .../src/sgattrib/alphaTransformTransition.cxx | 1 + panda/src/sgattrib/fogTransition.cxx | 3 +- panda/src/sgraphutil/quickRenderTraverser.cxx | 4 +- panda/src/vrpn/vrpnClient.cxx | 5 +- 36 files changed, 2235 insertions(+), 1434 deletions(-) create mode 100644 panda/src/express/dcast.T create mode 100644 panda/src/express/dcast.h create mode 100644 panda/src/express/register_type.I create mode 100644 panda/src/express/register_type.cxx create mode 100644 panda/src/express/register_type.h rename panda/src/{putil => express}/test_types.cxx (99%) create mode 100644 panda/src/express/typeRegistry.I create mode 100644 panda/src/express/typeRegistry.cxx create mode 100644 panda/src/express/typeRegistry.h create mode 100644 panda/src/express/typeRegistryNode.I create mode 100644 panda/src/express/typeRegistryNode.cxx create mode 100644 panda/src/express/typeRegistryNode.h diff --git a/panda/src/dgraph/buttonEventDataTransition.cxx b/panda/src/dgraph/buttonEventDataTransition.cxx index 3b41d27a56..5beca004fc 100644 --- a/panda/src/dgraph/buttonEventDataTransition.cxx +++ b/panda/src/dgraph/buttonEventDataTransition.cxx @@ -22,6 +22,7 @@ #include "indent.h" #include "modifierButtons.h" +#include "dcast.h" #include diff --git a/panda/src/egg/eggBinMaker.cxx b/panda/src/egg/eggBinMaker.cxx index a1bbc1d675..f978663408 100644 --- a/panda/src/egg/eggBinMaker.cxx +++ b/panda/src/egg/eggBinMaker.cxx @@ -21,7 +21,8 @@ #include "eggGroup.h" #include "eggBin.h" -#include +#include "dcast.h" +#include "notify.h" TypeHandle EggBinMaker::_type_handle; diff --git a/panda/src/egg/eggPolysetMaker.h b/panda/src/egg/eggPolysetMaker.h index e1b2dff073..9a4ef7a2d3 100644 --- a/panda/src/egg/eggPolysetMaker.h +++ b/panda/src/egg/eggPolysetMaker.h @@ -19,10 +19,12 @@ #ifndef EGGPOLYSETMAKER_H #define EGGPOLYSETMAKER_H -#include +#include "pandabase.h" #include "eggBinMaker.h" +#include "dcast.h" + /////////////////////////////////////////////////////////////////// // Class : EggPolysetMaker // Description : A specialization on EggBinMaker for making polysets diff --git a/panda/src/egg/parser.yxx b/panda/src/egg/parser.yxx index 5b994f3612..3ffed148e9 100644 --- a/panda/src/egg/parser.yxx +++ b/panda/src/egg/parser.yxx @@ -29,13 +29,13 @@ #include "pt_EggTexture.h" #include "pt_EggMaterial.h" -#include -#include -#include -#include -#include - +#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 diff --git a/panda/src/express/Sources.pp b/panda/src/express/Sources.pp index 56cc3b62a9..2b4e52e62e 100644 --- a/panda/src/express/Sources.pp +++ b/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 + diff --git a/panda/src/express/dcast.T b/panda/src/express/dcast.T new file mode 100644 index 0000000000..6b9002db79 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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 +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 +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 +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 +INLINE WantType * +_dcast_ref(WantType *&, TypedObject *ptr) { + return _dcast((WantType *)NULL, ptr); +} + +template +INLINE const WantType * +_dcast_ref(WantType *&, const TypedObject *ptr) { + return _dcast((WantType *)NULL, ptr); +} diff --git a/panda/src/express/dcast.h b/panda/src/express/dcast.h new file mode 100644 index 0000000000..06ccdd427d --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DCAST_H +#define DCAST_H + +#include "pandabase.h" + +#include "typeHandle.h" +#include "typedObject.h" + +#if defined(_DEBUG) && defined(_WIN32) +#include // 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 +INLINE WantType *_dcast(WantType *, TypedObject *ptr); +template +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 +INLINE WantType *_dcast_ref(WantType *&, TypedObject *ptr); +template +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 diff --git a/panda/src/express/express_composite2.cxx b/panda/src/express/express_composite2.cxx index 21caf0d68a..01046a91eb 100644 --- a/panda/src/express/express_composite2.cxx +++ b/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" diff --git a/panda/src/express/register_type.I b/panda/src/express/register_type.I new file mode 100644 index 0000000000..18de37205a --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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; +} diff --git a/panda/src/express/register_type.cxx b/panda/src/express/register_type.cxx new file mode 100644 index 0000000000..b3228aeb99 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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*"); + } +} + + diff --git a/panda/src/express/register_type.h b/panda/src/express/register_type.h new file mode 100644 index 0000000000..d1c493137e --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 +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 +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 diff --git a/panda/src/putil/test_types.cxx b/panda/src/express/test_types.cxx similarity index 99% rename from panda/src/putil/test_types.cxx rename to panda/src/express/test_types.cxx index e4ff561646..8fa486ab22 100644 --- a/panda/src/putil/test_types.cxx +++ b/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 { diff --git a/panda/src/express/typeHandle.I b/panda/src/express/typeHandle.I index d7d2447d61..296d11e6f2 100644 --- a/panda/src/express/typeHandle.I +++ b/panda/src/express/typeHandle.I @@ -16,11 +16,6 @@ // //////////////////////////////////////////////////////////////////// -#include "config_express.h" - -#if defined(_DEBUG) && defined(_WIN32) -#include -#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 -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 -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 -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 -INLINE WantType * -_dcast_ref(WantType *&, TypedObject *ptr) { - return _dcast((WantType *)NULL, ptr); -} - -template -INLINE const WantType * -_dcast_ref(WantType *&, const TypedObject *ptr) { - return _dcast((WantType *)NULL, ptr); -} diff --git a/panda/src/express/typeHandle.cxx b/panda/src/express/typeHandle.cxx index 04dde372a9..b53b38d0f2 100644 --- a/panda/src/express/typeHandle.cxx +++ b/panda/src/express/typeHandle.cxx @@ -17,687 +17,6 @@ //////////////////////////////////////////////////////////////////// #include "typeHandle.h" -#include "typedObject.h" -#include "indent.h" -#include "config_express.h" - -#include - -// 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(); -} - diff --git a/panda/src/express/typeHandle.h b/panda/src/express/typeHandle.h index 386a420371..dbc1f90a41 100644 --- a/panda/src/express/typeHandle.h +++ b/panda/src/express/typeHandle.h @@ -19,15 +19,11 @@ #ifndef TYPEHANDLE_H #define TYPEHANDLE_H -#include +#include "pandabase.h" -#include +#include "notify.h" -#include -#include "pvector.h" -#include "pmap.h" -#include "pset.h" -#include +#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 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 HandleRegistry; - HandleRegistry _handle_registry; - - typedef pmap NameRegistry; - NameRegistry _name_registry; - - typedef pvector 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 -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 -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" diff --git a/panda/src/express/typeRegistry.I b/panda/src/express/typeRegistry.I new file mode 100644 index 0000000000..620de45c1e --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +#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); +} diff --git a/panda/src/express/typeRegistry.cxx b/panda/src/express/typeRegistry.cxx new file mode 100644 index 0000000000..eabf38335a --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "typeRegistry.h" +#include "typedObject.h" +#include "indent.h" +#include "config_express.h" + +#include + +// 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 + diff --git a/panda/src/express/typeRegistry.h b/panda/src/express/typeRegistry.h new file mode 100644 index 0000000000..11d665d1c7 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 HandleRegistry; + HandleRegistry _handle_registry; + + typedef pmap NameRegistry; + NameRegistry _name_registry; + + typedef pvector RootClasses; + RootClasses _root_classes; + + bool _derivations_fresh; + + static TypeRegistry *_global_pointer; +}; + +#include "typeRegistry.I" + +#endif diff --git a/panda/src/express/typeRegistryNode.I b/panda/src/express/typeRegistryNode.I new file mode 100644 index 0000000000..0d5c4bc0cb --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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 ©) : + _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 ©) { + _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); +} diff --git a/panda/src/express/typeRegistryNode.cxx b/panda/src/express/typeRegistryNode.cxx new file mode 100644 index 0000000000..edcc5f41d5 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "typeRegistryNode.h" + +#include + +// 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; +} diff --git a/panda/src/express/typeRegistryNode.h b/panda/src/express/typeRegistryNode.h new file mode 100644 index 0000000000..91fba533ce --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 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 ©); + INLINE void operator = (const Inherit ©); + + 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 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 diff --git a/panda/src/express/typedObject.h b/panda/src/express/typedObject.h index 6997d01b23..ca562c1297 100644 --- a/panda/src/express/typedObject.h +++ b/panda/src/express/typedObject.h @@ -19,9 +19,10 @@ #ifndef TYPEDOBJECT_H #define TYPEDOBJECT_H -#include +#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 -INLINE WantType *_dcast(WantType *, TypedObject *ptr); -template -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 -INLINE WantType *_dcast_ref(WantType *&, TypedObject *ptr); -template -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 diff --git a/panda/src/glgsg/glGraphicsStateGuardian.cxx b/panda/src/glgsg/glGraphicsStateGuardian.cxx index e600a9db0e..fc1a544beb 100644 --- a/panda/src/glgsg/glGraphicsStateGuardian.cxx +++ b/panda/src/glgsg/glGraphicsStateGuardian.cxx @@ -22,54 +22,55 @@ #include "glGeomNodeContext.h" #include "config_glgsg.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#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 #if 0 diff --git a/panda/src/graph/nodeTransition.h b/panda/src/graph/nodeTransition.h index 9bb3d693e8..e5547b98dd 100644 --- a/panda/src/graph/nodeTransition.h +++ b/panda/src/graph/nodeTransition.h @@ -19,11 +19,12 @@ #ifndef NODETRANSITION_H #define NODETRANSITION_H -#include +#include "pandabase.h" #include "graphHashGenerator.h" -#include +#include "pset.h" +#include "typedWritableReferenceCount.h" class Node; class NodeTransitions; diff --git a/panda/src/graph/nodeTransitions.h b/panda/src/graph/nodeTransitions.h index 610316d91d..f2e9e5125e 100644 --- a/panda/src/graph/nodeTransitions.h +++ b/panda/src/graph/nodeTransitions.h @@ -19,11 +19,12 @@ #ifndef NODETRANSITIONS_H #define NODETRANSITIONS_H -#include +#include "pandabase.h" #include "nodeTransition.h" -#include +#include "pointerTo.h" +#include "dcast.h" #include "pmap.h" diff --git a/panda/src/graph/nullLevelState.h b/panda/src/graph/nullLevelState.h index fc164cc4bb..536d15fad0 100644 --- a/panda/src/graph/nullLevelState.h +++ b/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 diff --git a/panda/src/graph/nullTransitionWrapper.I b/panda/src/graph/nullTransitionWrapper.I index 8a80725437..bac307e260 100644 --- a/panda/src/graph/nullTransitionWrapper.I +++ b/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; } diff --git a/panda/src/graph/nullTransitionWrapper.h b/panda/src/graph/nullTransitionWrapper.h index 9088e55895..839c646392 100644 --- a/panda/src/graph/nullTransitionWrapper.h +++ b/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 ©); - INLINE_GRAPH void operator = (const NullTransitionWrapper ©); + INLINE NullTransitionWrapper(); + INLINE NullTransitionWrapper(const NullTransitionWrapper ©); + INLINE void operator = (const NullTransitionWrapper ©); - 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 diff --git a/panda/src/mathutil/boundingSphere.cxx b/panda/src/mathutil/boundingSphere.cxx index 37989ae38e..5ab4884c1b 100644 --- a/panda/src/mathutil/boundingSphere.cxx +++ b/panda/src/mathutil/boundingSphere.cxx @@ -20,6 +20,7 @@ #include "boundingHexahedron.h" #include "boundingLine.h" #include "config_mathutil.h" +#include "dcast.h" #include #include diff --git a/panda/src/pnmimage/pnmFileTypeRegistry.cxx b/panda/src/pnmimage/pnmFileTypeRegistry.cxx index dfef0f13df..f38f8ba578 100644 --- a/panda/src/pnmimage/pnmFileTypeRegistry.cxx +++ b/panda/src/pnmimage/pnmFileTypeRegistry.cxx @@ -20,8 +20,9 @@ #include "pnmFileType.h" #include "config_pnmimage.h" -#include -#include +#include "string_utils.h" +#include "indent.h" +#include "pset.h" #include diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 494fcabed5..5ebe697098 100644 --- a/panda/src/putil/Sources.pp +++ b/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 - diff --git a/panda/src/putil/bamReader.h b/panda/src/putil/bamReader.h index 55fc9c9dac..cb1241fbca 100644 --- a/panda/src/putil/bamReader.h +++ b/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 diff --git a/panda/src/sgattrib/alphaTransformTransition.cxx b/panda/src/sgattrib/alphaTransformTransition.cxx index 3a0ce602f9..a99f6c6326 100644 --- a/panda/src/sgattrib/alphaTransformTransition.cxx +++ b/panda/src/sgattrib/alphaTransformTransition.cxx @@ -20,6 +20,7 @@ #include "graphicsStateGuardianBase.h" #include "indent.h" +#include "dcast.h" TypeHandle AlphaTransformTransition::_type_handle; diff --git a/panda/src/sgattrib/fogTransition.cxx b/panda/src/sgattrib/fogTransition.cxx index 2814e1a672..94d4c74d78 100644 --- a/panda/src/sgattrib/fogTransition.cxx +++ b/panda/src/sgattrib/fogTransition.cxx @@ -18,7 +18,8 @@ #include "fogTransition.h" -#include +#include "dcast.h" +#include "indent.h" TypeHandle FogTransition::_type_handle; diff --git a/panda/src/sgraphutil/quickRenderTraverser.cxx b/panda/src/sgraphutil/quickRenderTraverser.cxx index 0cc18ec6c6..9487876567 100644 --- a/panda/src/sgraphutil/quickRenderTraverser.cxx +++ b/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); diff --git a/panda/src/vrpn/vrpnClient.cxx b/panda/src/vrpn/vrpnClient.cxx index 99abbca2e9..2ede313a93 100644 --- a/panda/src/vrpn/vrpnClient.cxx +++ b/panda/src/vrpn/vrpnClient.cxx @@ -27,8 +27,9 @@ #include "vrpnDialDevice.h" #include "config_vrpn.h" -#include -#include +#include "dcast.h" +#include "string_utils.h" +#include "indent.h" TypeHandle VrpnClient::_type_handle;