Browse Source

Eliminate the requirement for RTTI

rdb 6 years ago
parent
commit
8230f46414

+ 41 - 0
dtool/src/dtoolbase/register_type.I

@@ -112,3 +112,44 @@ register_dynamic_type(const std::string &name,
   registry->record_derivation(type_handle, parent4);
   return type_handle;
 }
+
+/**
+ * This is a helper that returns the type name for any given type.
+ */
+template<class T>
+INLINE std::basic_string<char>
+_get_type_name() {
+#if defined(__clang__)
+  static const size_t entire_size = sizeof(__PRETTY_FUNCTION__) - 1;
+  static const size_t prefix_size = sizeof("std::basic_string<char> _get_type_name() [T = ") - 1;
+  static const size_t suffix_size = sizeof("]") - 1;
+  return std::string(__PRETTY_FUNCTION__ + prefix_size, entire_size - prefix_size - suffix_size);
+#elif defined(__GNUC__)
+  // NB. Since GCC will otherwise include the definition of std::string, we are
+  // declaring this function as returning std::basic_string<char> instead.
+  static const size_t entire_size = sizeof(__PRETTY_FUNCTION__) - 1;
+#ifdef _GLIBCXX_USE_CXX11_ABI
+  static const size_t prefix_size = sizeof("std::__cxx11::basic_string<char> _get_type_name() [with T = ") - 1;
+#else
+  static const size_t prefix_size = sizeof("std::basic_string<char> _get_type_name() [with T = ") - 1;
+#endif
+  static const size_t suffix_size = sizeof("]") - 1;
+  return std::string(__PRETTY_FUNCTION__ + prefix_size, entire_size - prefix_size - suffix_size);
+#elif defined(_MSC_VER)
+  // MSVC allows us to use RTTI to get the type name without having it enabled.
+  // However, we do have to strip the "class" or "struct" prefix.
+  std::string type_name = typeid(T).name();
+  size_t space = type_name.find(' ');
+  if (space != std::string::npos) {
+    return type_name.substr(space + 1);
+  } else {
+    return type_name;
+  }
+#elif defined(HAVE_RTTI) && !defined(__EDG__)
+  // If we have RTTI, we can use it to determine the name of the base type.
+  // MSVC allows us to use this with RTTI disabled as well.
+  return typeid(T).name();
+#else
+  return "unknown";
+#endif
+}

+ 16 - 0
dtool/src/dtoolbase/register_type.h

@@ -19,6 +19,10 @@
 #include "typeHandle.h"
 #include "typeRegistry.h"
 
+#if defined(HAVE_RTTI) && !defined(__clang__) && !defined(__GNUC__)
+#include <typeinfo>
+#endif
+
 /**
  * This inline function is just a convenient way to call
  * TypeRegistry::register_type(), along with zero to four
@@ -75,6 +79,18 @@ register_dynamic_type(const std::string &name,
                       TypeHandle parent3, TypeHandle parent4);
 
 
+/**
+ * This is a helper that returns the type name for any given type.
+ */
+template<class T>
+INLINE std::basic_string<char>
+_get_type_name();
+
+// The macro get_type_name(type) is defined to make getting the type name
+// associated with a particular type a bit cleaner.
+#define get_type_name(type) _get_type_name<type>()
+
+
 // A few system-wide TypeHandles are defined for some basic types.
 extern TypeHandle EXPCL_DTOOL_DTOOLBASE long_type_handle;
 extern TypeHandle EXPCL_DTOOL_DTOOLBASE int_type_handle;

+ 2 - 3
makepanda/makepanda.py

@@ -1309,9 +1309,8 @@ def CompileCxx(obj,src,opts):
 
             target = GetTarget()
             if 'RTTI' not in opts and target != "darwin":
-                # We always disable RTTI on Android for memory usage reasons.
-                if optlevel >= 4 or target == "android":
-                    cmd += " -fno-rtti"
+                # We always disable RTTI nowadays.
+                cmd += " -fno-rtti"
 
         if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm") and arch != 'aarch64':
             cmd += " -msse2"

+ 2 - 2
panda/src/express/memoryUsagePointers.cxx

@@ -111,8 +111,8 @@ get_type(size_t n) const {
 /**
  * Returns the type name of the nth pointer, if it is known.
  */
-std::string MemoryUsagePointers::
-get_type_name(size_t n) const {
+std::string (MemoryUsagePointers::
+get_type_name)(size_t n) const {
 #ifdef DO_MEMORY_USAGE
   nassertr(n < get_num_pointers(), "");
   return get_type(n).get_name();

+ 1 - 1
panda/src/express/memoryUsagePointers.h

@@ -47,7 +47,7 @@ PUBLISHED:
   MAKE_SEQ(get_typed_pointers, get_num_pointers, get_typed_pointer);
 
   TypeHandle get_type(size_t n) const;
-  std::string get_type_name(size_t n) const;
+  std::string (get_type_name)(size_t n) const;
   double get_age(size_t n) const;
 
 #ifdef DO_MEMORY_USAGE

+ 1 - 7
panda/src/express/nodeReferenceCount.I

@@ -213,13 +213,7 @@ NodeRefCountObj(const Base &copy) : Base(copy) {
 template<class Base>
 void NodeRefCountObj<Base>::
 init_type() {
-#if defined(HAVE_RTTI) && !defined(__EDG__)
-  // If we have RTTI, we can determine the name of the base type.
-  std::string base_name = typeid(Base).name();
-#else
-  std::string base_name = "unknown";
-#endif
-
+  std::string base_name = get_type_name(Base);
   TypeHandle base_type = register_dynamic_type(base_name);
 
   ReferenceCount::init_type();

+ 1 - 7
panda/src/express/referenceCount.I

@@ -409,13 +409,7 @@ RefCountObj(const Base &copy) : Base(copy) {
 template<class Base>
 void RefCountObj<Base>::
 init_type() {
-#if defined(HAVE_RTTI) && !defined(__EDG__)
-  // If we have RTTI, we can determine the name of the base type.
-  std::string base_name = typeid(Base).name();
-#else
-  std::string base_name = "unknown";
-#endif
-
+  std::string base_name = get_type_name(Base);
   TypeHandle base_type = register_dynamic_type(base_name);
 
   ReferenceCount::init_type();

+ 0 - 4
panda/src/express/referenceCount.h

@@ -26,10 +26,6 @@
 
 #include <stdlib.h>
 
-#ifdef HAVE_RTTI
-#include <typeinfo>
-#endif
-
 /**
  * A base class for all things that want to be reference-counted.
  * ReferenceCount works in conjunction with PointerTo to automatically delete

+ 2 - 14
panda/src/putil/copyOnWriteObject.I

@@ -128,13 +128,7 @@ make_cow_copy() {
 template<class Base>
 void CopyOnWriteObj<Base>::
 init_type() {
-#if defined(HAVE_RTTI) && !defined(__EDG__)
-  // If we have RTTI, we can determine the name of the base type.
-  std::string base_name = typeid(Base).name();
-#else
-  std::string base_name = "unknown";
-#endif
-
+  std::string base_name = get_type_name(Base);
   TypeHandle base_type = register_dynamic_type(base_name);
 
   CopyOnWriteObject::init_type();
@@ -188,13 +182,7 @@ make_cow_copy() {
 template<class Base, class Param1>
 void CopyOnWriteObj1<Base, Param1>::
 init_type() {
-#if defined(HAVE_RTTI) && !defined(__EDG__)
-  // If we have RTTI, we can determine the name of the base type.
-  std::string base_name = typeid(Base).name();
-#else
-  std::string base_name = "unknown";
-#endif
-
+  std::string base_name = get_type_name(Base);
   TypeHandle base_type = register_dynamic_type(base_name);
 
   CopyOnWriteObject::init_type();

+ 2 - 2
pandatool/src/xfile/xFileDataNode.cxx

@@ -59,7 +59,7 @@ is_standard_object(const std::string &template_name) const {
  * Returns a string that represents the type of object this data object
  * represents.
  */
-std::string XFileDataNode::
-get_type_name() const {
+std::string (XFileDataNode::
+get_type_name)() const {
   return _template->get_name();
 }

+ 1 - 1
pandatool/src/xfile/xFileDataNode.h

@@ -37,7 +37,7 @@ public:
 
   virtual bool is_object() const;
   virtual bool is_standard_object(const std::string &template_name) const;
-  virtual std::string get_type_name() const;
+  virtual std::string (get_type_name)() const;
 
   INLINE const XFileDataNode &get_data_child(int n) const;
 

+ 9 - 9
pandatool/src/xfile/xFileDataObject.cxx

@@ -45,8 +45,8 @@ is_complex_object() const {
  * Returns a string that represents the type of object this data object
  * represents.
  */
-string XFileDataObject::
-get_type_name() const {
+string (XFileDataObject::
+get_type_name)() const {
   return get_type().get_name();
 }
 
@@ -189,7 +189,7 @@ write_data(std::ostream &out, int indent_level, const char *) const {
 void XFileDataObject::
 set_int_value(int int_value) {
   xfile_cat.error()
-    << get_type_name() << " does not support integer values.\n";
+    << (get_type_name)() << " does not support integer values.\n";
 }
 
 /**
@@ -198,7 +198,7 @@ set_int_value(int int_value) {
 void XFileDataObject::
 set_double_value(double double_value) {
   xfile_cat.error()
-    << get_type_name() << " does not support floating-point values.\n";
+    << (get_type_name)() << " does not support floating-point values.\n";
 }
 
 /**
@@ -207,7 +207,7 @@ set_double_value(double double_value) {
 void XFileDataObject::
 set_string_value(const string &string_value) {
   xfile_cat.error()
-    << get_type_name() << " does not support string values.\n";
+    << (get_type_name)() << " does not support string values.\n";
 }
 
 /**
@@ -219,7 +219,7 @@ void XFileDataObject::
 store_double_array(int num_elements, const double *values) {
   if (get_num_elements() != num_elements) {
     xfile_cat.error()
-      << get_type_name() << " does not accept "
+      << (get_type_name)() << " does not accept "
       << num_elements << " values.\n";
     return;
   }
@@ -263,7 +263,7 @@ void XFileDataObject::
 get_double_array(int num_elements, double *values) const {
   if (get_num_elements() != num_elements) {
     xfile_cat.error()
-      << get_type_name() << " does not contain "
+      << (get_type_name)() << " does not contain "
       << num_elements << " values.\n";
     return;
   }
@@ -289,7 +289,7 @@ XFileDataObject *XFileDataObject::
 get_element(int n) {
   xfile_cat.warning()
     << "Looking for [" << n << "] within data object of type "
-    << get_type_name() << ", does not support nested objects.\n";
+    << (get_type_name)() << ", does not support nested objects.\n";
   return nullptr;
 }
 
@@ -301,6 +301,6 @@ XFileDataObject *XFileDataObject::
 get_element(const string &name) {
   xfile_cat.warning()
     << "Looking for [\"" << name << "\"] within data object of type "
-    << get_type_name() << ", does not support nested objects.\n";
+    << (get_type_name)() << ", does not support nested objects.\n";
   return nullptr;
 }

+ 1 - 1
pandatool/src/xfile/xFileDataObject.h

@@ -35,7 +35,7 @@ public:
   INLINE const XFileDataDef *get_data_def() const;
 
   virtual bool is_complex_object() const;
-  virtual std::string get_type_name() const;
+  virtual std::string (get_type_name)() const;
 
   INLINE void operator = (int int_value);
   INLINE void operator = (double double_value);

+ 26 - 0
tests/dtoolbase/test_typeregistry.py

@@ -0,0 +1,26 @@
+from panda3d.core import TypeRegistry
+import pytest
+
+
+def test_get_type_name():
+    # We test the get_type_name macro by checking for the existence of a type
+    # that has been registered using it, and that it has the name we expect
+    # (without weird extra mangling characters)
+
+    # The type we're testing is registered by EggNode.
+    pytest.importorskip("panda3d.egg")
+
+    registry = TypeRegistry.ptr()
+
+    found = False
+    for type in registry.typehandles:
+        if type.name.startswith('RefCountObj<') and 'LMatrix4d' in type.name:
+            found = True
+            break
+
+    # This is an assert, not a skip, so that we are sure to change the example
+    # if it ever becomes invalid
+    assert found
+
+    assert type.name == 'RefCountObj<LMatrix4d>'
+    assert any(parent.name == 'LMatrix4d' for parent in type.parent_classes)