optimize is_of_type(), in theory

This commit is contained in:
David Rose 2001-08-07 02:00:46 +00:00
parent 06cb23cd73
commit 764aea593e
36 changed files with 2235 additions and 1434 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

127
panda/src/express/dcast.T Normal file
View File

@ -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<class WantType>
INLINE TypeHandle
_dcast_get_typehandle(WantType *) {
TypeHandle handle = WantType::get_class_type();
if (handle == TypeHandle::none()) {
// This type handle is unregistered. Oops!
WantType::init_type();
handle = WantType::get_class_type();
express_cat->warning()
<< "Type " << handle << " was unregistered!\n";
}
return handle;
}
////////////////////////////////////////////////////////////////////
// Function: _dcast
// Description: The implementation of the DCAST macro, this checks
// the actual type of the pointer before performing a
// downcast operation. In NDEBUG mode, it simply
// downcasts.
//
// This flavor of _dcast works on non-const pointers.
////////////////////////////////////////////////////////////////////
template<class WantType>
INLINE WantType *
_dcast(WantType *, TypedObject *ptr) {
#ifndef NDEBUG
TypeHandle want_handle = _dcast_get_typehandle((WantType *)0);
#if defined(_DEBUG) && defined(_WIN32)
if ((ptr == (TypedObject *)NULL) || IsBadWritePtr(ptr,sizeof(TypedObject))) {
#else
if (ptr == (TypedObject *)NULL) {
#endif
express_cat->warning()
<< "Attempt to cast NULL pointer to " << want_handle << "\n";
return (WantType *)NULL;
}
if (!ptr->is_of_type(want_handle)) {
express_cat->error()
<< "Attempt to cast pointer from " << ptr->get_type()
<< " to " << want_handle << "\n";
if (ptr->get_type() == TypedObject::get_class_type()) {
express_cat->error(false)
<< "Perhaps pointer was inadvertently deleted?\n";
}
return (WantType *)NULL;
}
#endif
return (WantType *)ptr;
}
////////////////////////////////////////////////////////////////////
// Function: _dcast
// Description: The implementation of the DCAST macro, this checks
// the actual type of the pointer before performing a
// downcast operation. In NDEBUG mode, it simply
// downcasts.
//
// This flavor of _dcast works on const pointers.
////////////////////////////////////////////////////////////////////
template<class WantType>
INLINE const WantType *
_dcast(WantType *, const TypedObject *ptr) {
#ifndef NDEBUG
TypeHandle want_handle = _dcast_get_typehandle((WantType *)0);
if (ptr == (const TypedObject *)NULL) {
express_cat->warning()
<< "Attempt to cast NULL pointer to " << want_handle << "\n";
return (const WantType *)NULL;
}
if (!ptr->is_of_type(want_handle)) {
express_cat->error()
<< "Attempt to cast pointer from " << ptr->get_type()
<< " to " << want_handle << "\n";
if (ptr->get_type() == TypedObject::get_class_type()) {
express_cat->error(false)
<< "Perhaps pointer was inadvertently deleted?\n";
}
return (const WantType *)NULL;
}
#endif
return (const WantType *)ptr;
}
////////////////////////////////////////////////////////////////////
// Function: _dcast_ref
// Description: Similar to the above, with a pointer reference as the
// first parameter. Just for fiddly compiler reasons;
// the reference isn't used.
////////////////////////////////////////////////////////////////////
template<class WantType>
INLINE WantType *
_dcast_ref(WantType *&, TypedObject *ptr) {
return _dcast((WantType *)NULL, ptr);
}
template<class WantType>
INLINE const WantType *
_dcast_ref(WantType *&, const TypedObject *ptr) {
return _dcast((WantType *)NULL, ptr);
}

90
panda/src/express/dcast.h Normal file
View File

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

View File

@ -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"

View File

@ -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;
}

View File

@ -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*");
}
}

View File

@ -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<class T>
INLINE TypeHandle _get_type_handle(const T *) {
return T::get_class_type();
}
template<>
INLINE TypeHandle _get_type_handle(const long *) {
return long_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const int *) {
return int_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const short *) {
return short_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const char *) {
return char_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const bool *) {
return bool_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const double *) {
return double_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const float *) {
return float_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const long * const *) {
return long_p_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const int * const *) {
return int_p_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const short * const *) {
return short_p_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const char * const *) {
return char_p_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const bool * const *) {
return bool_p_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const double * const *) {
return double_p_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const float * const *) {
return float_p_type_handle;
}
template<>
INLINE TypeHandle _get_type_handle(const void * const *) {
return void_p_type_handle;
}
// The macro get_type_handle(type) is defined to make getting the type
// handle associated with a particular type a bit cleaner.
#define get_type_handle(type) _get_type_handle((const type *)0)
// The following template function and its specializations can be used
// to call init() on any unknown type. Handy for use within a
// template class.
template<class T>
INLINE void _do_init_type(const T *) {
T::init_type();
}
template<>
INLINE void _do_init_type(const long *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const int *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const short *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const char *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const bool *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const double *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const float *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const long * const *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const int * const *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const short * const *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const char * const *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const bool * const *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const double * const *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const float * const *) {
init_system_type_handles();
}
template<>
INLINE void _do_init_type(const void * const *) {
init_system_type_handles();
}
#define do_init_type(type) _do_init_type((const type *)0)
#include "register_type.I"
#endif

View File

@ -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 {

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

@ -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<TypeRegistryNode *> HandleRegistry;
HandleRegistry _handle_registry;
typedef pmap<string, TypeRegistryNode *> NameRegistry;
NameRegistry _name_registry;
typedef pvector<TypeRegistryNode *> RootClasses;
RootClasses _root_classes;
bool _derivations_fresh;
static TypeRegistry *_global_pointer;
};
#include "typeRegistry.I"
#endif

View File

@ -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 &copy) :
_top(copy._top),
_mask(copy._mask),
_bits(copy._bits)
{
}
////////////////////////////////////////////////////////////////////
// Function: TypeRegistryNode::Inherit::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void TypeRegistryNode::Inherit::
operator = (const TypeRegistryNode::Inherit &copy) {
_top = copy._top;
_mask = copy._mask;
_bits = copy._bits;
}
////////////////////////////////////////////////////////////////////
// Function: TypeRegistryNode::Inherit::Ordering operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool TypeRegistryNode::Inherit::
operator < (const Inherit &other) const {
return _top < other._top;
}
////////////////////////////////////////////////////////////////////
// Function: TypeRegistryNode::Inherit::is_derived_from
// Access: Public
// Description: Assuming the two Inherit objects share the same
// subtree top, this returns true if the bitmasks
// indicate that child inherits from base, or false
// otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool TypeRegistryNode::Inherit::
is_derived_from(const TypeRegistryNode::Inherit &child,
const TypeRegistryNode::Inherit &base) {
nassertr(child._top == base._top, false);
// Child derives from base if and only if its subtree mask contains
// more bits (or the same number of bits), and the n low-order
// subtree bits that are in common are identical.
return ((child._mask & base._mask) == base._mask &&
(child._bits & base._mask) == base._bits);
}

View File

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

View File

@ -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<TypeRegistryNode *> Classes;
Classes _parent_classes;
Classes _child_classes;
private:
typedef int SubtreeMaskType;
// This class defines the inheritance relationship of this node from
// some ancestor denoted as a "subtree top" node. This is usually
// the nearest ancestor that has multiple inheritance.
class Inherit {
public:
INLINE Inherit();
INLINE Inherit(TypeRegistryNode *top, int bit_count,
SubtreeMaskType bits);
INLINE Inherit(const Inherit &copy);
INLINE void operator = (const Inherit &copy);
INLINE bool operator < (const Inherit &other) const;
INLINE static bool is_derived_from(const Inherit &child, const Inherit &base);
TypeRegistryNode *_top;
SubtreeMaskType _mask;
SubtreeMaskType _bits;
};
typedef pvector<Inherit> TopInheritance;
void r_build_subtrees(TypeRegistryNode *top,
int bit_count, SubtreeMaskType bits);
TopInheritance::const_iterator
find_top_inherit(const TypeRegistryNode *base) const;
static bool check_derived_from(const TypeRegistryNode *child,
const TypeRegistryNode *base);
Inherit _inherit;
// The _top_inheritance member is only filled for nodes that are
// denoted as "subtree top" nodes. It represents the complete set
// of subtree_top nodes that this node inherits from, directly or
// indirectly.
TopInheritance _top_inheritance;
// _visit_count is only used during r_build_subtree().
int _visit_count;
};
#include "typeRegistryNode.I"
#endif

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

@ -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);

View File

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