Panda3D
|
00001 // Filename: deletedChain.h 00002 // Created by: drose (01Apr06) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #ifndef DELETEDCHAIN_H 00016 #define DELETEDCHAIN_H 00017 00018 #include "dtoolbase.h" 00019 #include "deletedBufferChain.h" 00020 #include <assert.h> 00021 00022 //////////////////////////////////////////////////////////////////// 00023 // Class : DeletedChain 00024 // Description : This template class can be used to provide faster 00025 // allocation/deallocation for many Panda objects. It 00026 // works by maintaining a linked list of deleted objects 00027 // that are all of the same type; when a new object is 00028 // allocated that matches that type, the same space is 00029 // just reused. 00030 // 00031 // This class is actually a layer on top of 00032 // DeletedBufferChain, which handles the actual 00033 // allocation. This class just provides the 00034 // typecasting. 00035 // 00036 // Of course, this trick of maintaining the deleted 00037 // object chain won't work in the presence of 00038 // polymorphism, where you might have many classes that 00039 // derive from a base class, and all of them have a 00040 // different size--unless you instantiate a DeletedChain 00041 // for *every* kind of derived class. The 00042 // ALLOC_DELETED_CHAIN macro, below, is designed to make 00043 // this easy. 00044 //////////////////////////////////////////////////////////////////// 00045 template<class Type> 00046 class DeletedChain { 00047 public: 00048 INLINE Type *allocate(size_t size, TypeHandle type_handle); 00049 INLINE void deallocate(Type *ptr, TypeHandle type_handle); 00050 00051 INLINE bool validate(const Type *ptr); 00052 00053 static INLINE ReferenceCount *make_ref_ptr(void *ptr); 00054 static INLINE ReferenceCount *make_ref_ptr(ReferenceCount *ptr); 00055 00056 private: 00057 INLINE void init_deleted_chain(); 00058 00059 DeletedBufferChain *_chain; 00060 }; 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Class : StaticDeletedChain 00064 // Description : This template class is used to conveniently 00065 // declare a single instance of the DeletedChain 00066 // template object, above, for a particular type. 00067 // 00068 // It relies on the fact that the compiler and linker 00069 // should unify all references to this static pointer 00070 // for a given type, as per the C++ spec. However, this 00071 // sometimes fails; and if the compiler fails to do 00072 // this, it mostly won't be a big deal; it just means 00073 // there will be multiple unrelated chains of deleted 00074 // objects for a particular type. This is only a 00075 // problem if the code structure causes objects to be 00076 // allocated from one chain and freed to another, which 00077 // can lead to leaks. 00078 //////////////////////////////////////////////////////////////////// 00079 template<class Type> 00080 class StaticDeletedChain { 00081 public: 00082 INLINE static Type *allocate(size_t size, TypeHandle type_handle); 00083 INLINE static void deallocate(Type *ptr, TypeHandle type_handle); 00084 00085 INLINE static bool validate(const Type *ptr); 00086 00087 static DeletedChain<Type> _chain; 00088 }; 00089 00090 #ifdef USE_DELETED_CHAIN 00091 // Place this macro within a class definition to define appropriate 00092 // operator new and delete methods that take advantage of 00093 // DeletedChain. 00094 #define ALLOC_DELETED_CHAIN(Type) \ 00095 inline void *operator new(size_t size) { \ 00096 return (void *)StaticDeletedChain< Type >::allocate(size, get_type_handle(Type)); \ 00097 } \ 00098 inline void *operator new(size_t size, void *ptr) { \ 00099 return ptr; \ 00100 } \ 00101 inline void operator delete(void *ptr) { \ 00102 StaticDeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \ 00103 } \ 00104 inline void operator delete(void *, void *) { \ 00105 } \ 00106 inline static bool validate_ptr(const void *ptr) { \ 00107 return StaticDeletedChain< Type >::validate((const Type *)ptr); \ 00108 } 00109 00110 // Use this variant of the above macro in cases in which the compiler 00111 // fails to unify the static template pointers properly, to prevent 00112 // leaks. 00113 #define ALLOC_DELETED_CHAIN_DECL(Type) \ 00114 inline void *operator new(size_t size) { \ 00115 return (void *)_deleted_chain.allocate(size, get_type_handle(Type)); \ 00116 } \ 00117 inline void *operator new(size_t size, void *ptr) { \ 00118 return ptr; \ 00119 } \ 00120 inline void operator delete(void *ptr) { \ 00121 _deleted_chain.deallocate((Type *)ptr, get_type_handle(Type)); \ 00122 } \ 00123 inline void operator delete(void *, void *) { \ 00124 } \ 00125 inline static bool validate_ptr(const void *ptr) { \ 00126 return _deleted_chain.validate((const Type *)ptr); \ 00127 } \ 00128 static DeletedChain< Type > _deleted_chain; 00129 00130 // When you use ALLOC_DELETED_CHAIN_DECL in a class body, you must 00131 // also put this line in the .cxx file defining that class body. 00132 #define ALLOC_DELETED_CHAIN_DEF(Type) \ 00133 DeletedChain< Type > Type::_deleted_chain; 00134 00135 #else // USE_DELETED_CHAIN 00136 00137 #define ALLOC_DELETED_CHAIN(Type) \ 00138 inline static bool validate_ptr(const void *ptr) { \ 00139 return (ptr != NULL); \ 00140 } 00141 #define ALLOC_DELETED_CHAIN_DECL(Type) \ 00142 inline static bool validate_ptr(const void *ptr) { \ 00143 return (ptr != NULL); \ 00144 } 00145 #define ALLOC_DELETED_CHAIN_DEF(Type) 00146 00147 #endif // USE_DELETED_CHAIN 00148 00149 #include "deletedChain.T" 00150 00151 #endif 00152