Browse Source

express: support casting between compatible PointerTo types

This makes it possible to implicitly convert a PT of a derived type to a (C)PT of a base type, without needing to first convert it to a regular pointer.  This also applies to moves, which are now more efficient due to the lack of need for ref/unref pair even if the pointer type is not exactly the same.
rdb 7 years ago
parent
commit
23128e4695

+ 162 - 0
panda/src/express/pointerTo.I

@@ -39,6 +39,41 @@ PointerTo(PointerTo<T> &&from) noexcept :
 {
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T>::
+PointerTo(Y *ptr) noexcept :
+  PointerToBase<T>(ptr)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T>::
+PointerTo(const PointerTo<Y> &r) noexcept :
+  PointerToBase<T>(r.p())
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T>::
+PointerTo(PointerTo<Y> &&r) noexcept :
+  PointerToBase<T>(std::move(r))
+{
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */
@@ -49,6 +84,30 @@ operator = (PointerTo<T> &&from) noexcept {
   return *this;
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T> &PointerTo<T>::
+operator = (const PointerTo<Y> &r) noexcept {
+  this->reassign(r.p());
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE PointerTo<T> &PointerTo<T>::
+operator = (PointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */
@@ -172,6 +231,63 @@ ConstPointerTo(ConstPointerTo<T> &&from) noexcept :
 {
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(const Y *ptr) noexcept :
+  PointerToBase<T>((Y *)ptr)
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(const PointerTo<Y> &r) noexcept :
+  PointerToBase<T>(r.p())
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(const ConstPointerTo<Y> &r) noexcept :
+  PointerToBase<T>((Y *)r.p())
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(PointerTo<Y> &&r) noexcept :
+  PointerToBase<T>(std::move(r))
+{
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T>::
+ConstPointerTo(ConstPointerTo<Y> &&r) noexcept :
+  PointerToBase<T>(std::move(r))
+{
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */
@@ -192,6 +308,52 @@ operator = (ConstPointerTo<T> &&from) noexcept {
   return *this;
 }
 
+#ifndef CPPPARSER
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (const PointerTo<Y> &r) noexcept {
+  this->reassign(r.p());
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (const ConstPointerTo<Y> &r) noexcept {
+  this->reassign((Y *)r.p());
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (PointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+
+/**
+ *
+ */
+template<class T>
+template<class Y>
+ALWAYS_INLINE ConstPointerTo<T> &ConstPointerTo<T>::
+operator = (ConstPointerTo<Y> &&r) noexcept {
+  this->reassign(std::move(r));
+  return *this;
+}
+#endif  // !CPPPARSER
+
 /**
  *
  */

+ 34 - 0
panda/src/express/pointerTo.h

@@ -77,8 +77,21 @@ PUBLISHED:
 
 public:
   INLINE PointerTo(PointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE explicit PointerTo(Y *ptr) noexcept;
+  template<class Y>
+  ALWAYS_INLINE PointerTo(const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE PointerTo(PointerTo<Y> &&r) noexcept;
+
   INLINE PointerTo<T> &operator = (PointerTo<T> &&from) noexcept;
 
+  template<class Y>
+  ALWAYS_INLINE PointerTo<T> &operator = (const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE PointerTo<T> &operator = (PointerTo<Y> &&r) noexcept;
+
   constexpr To &operator *() const noexcept;
   constexpr To *operator -> () const noexcept;
   // MSVC.NET 2005 insists that we use T *, and not To *, here.
@@ -141,9 +154,30 @@ PUBLISHED:
 public:
   INLINE ConstPointerTo(PointerTo<T> &&from) noexcept;
   INLINE ConstPointerTo(ConstPointerTo<T> &&from) noexcept;
+
+  template<class Y>
+  ALWAYS_INLINE explicit ConstPointerTo(const Y *ptr) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(const ConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(PointerTo<Y> &&r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo(ConstPointerTo<Y> &&r) noexcept;
+
   INLINE ConstPointerTo<T> &operator = (PointerTo<T> &&from) noexcept;
   INLINE ConstPointerTo<T> &operator = (ConstPointerTo<T> &&from) noexcept;
 
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (const PointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (const ConstPointerTo<Y> &r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (PointerTo<Y> &&r) noexcept;
+  template<class Y>
+  ALWAYS_INLINE ConstPointerTo<T> &operator = (ConstPointerTo<Y> &&r) noexcept;
+
   constexpr const To &operator *() const noexcept;
   constexpr const To *operator -> () const noexcept;
   constexpr operator const T *() const noexcept;

+ 48 - 8
panda/src/express/pointerToBase.I

@@ -44,21 +44,36 @@ PointerToBase(const PointerToBase<T> &copy) {
  */
 template<class T>
 INLINE PointerToBase<T>::
-~PointerToBase() {
-  if (_void_ptr != nullptr) {
-    unref_delete((To *)_void_ptr);
-    _void_ptr = nullptr;
-  }
+PointerToBase(PointerToBase<T> &&from) noexcept {
+  _void_ptr = from._void_ptr;
+  from._void_ptr = nullptr;
 }
 
 /**
  *
  */
 template<class T>
+template<class Y>
 INLINE PointerToBase<T>::
-PointerToBase(PointerToBase<T> &&from) noexcept {
-  _void_ptr = from._void_ptr;
-  from._void_ptr = nullptr;
+PointerToBase(PointerToBase<Y> &&r) noexcept {
+  // If this next line gives an error, you are trying to convert a PointerTo
+  // from an incompatible type of another PointerTo.
+  To *ptr = (Y *)r._void_ptr;
+
+  this->_void_ptr = ptr;
+  r._void_ptr = nullptr;
+}
+
+/**
+ *
+ */
+template<class T>
+INLINE PointerToBase<T>::
+~PointerToBase() {
+  if (_void_ptr != nullptr) {
+    unref_delete((To *)_void_ptr);
+    _void_ptr = nullptr;
+  }
 }
 
 /**
@@ -84,6 +99,31 @@ reassign(PointerToBase<T> &&from) noexcept {
   }
 }
 
+/**
+ * Like above, but casts from a compatible pointer type.
+ */
+template<class T>
+template<class Y>
+INLINE void PointerToBase<T>::
+reassign(PointerToBase<Y> &&from) noexcept {
+  // Protect against self-move-assignment.
+  if (from._void_ptr != this->_void_ptr) {
+    To *old_ptr = (To *)this->_void_ptr;
+
+    // If there is a compile error on this line, it means you tried to assign
+    // an incompatible type.
+    To *new_ptr = (Y *)from._void_ptr;
+
+    this->_void_ptr = new_ptr;
+    from._void_ptr = nullptr;
+
+    // Now delete the old pointer.
+    if (old_ptr != nullptr) {
+      unref_delete(old_ptr);
+    }
+  }
+}
+
 /**
  * This is the main work of the PointerTo family.  When the pointer is
  * reassigned, decrement the old reference count and increment the new one.

+ 8 - 0
panda/src/express/pointerToBase.h

@@ -35,17 +35,25 @@ protected:
   INLINE PointerToBase(To *ptr);
   INLINE PointerToBase(const PointerToBase<T> &copy);
   INLINE PointerToBase(PointerToBase<T> &&from) noexcept;
+  template<class Y>
+  INLINE PointerToBase(PointerToBase<Y> &&r) noexcept;
+
   INLINE ~PointerToBase();
 
   INLINE void reassign(To *ptr);
   INLINE void reassign(const PointerToBase<To> &copy);
   INLINE void reassign(PointerToBase<To> &&from) noexcept;
+  template<class Y>
+  INLINE void reassign(PointerToBase<Y> &&from) noexcept;
 
   INLINE void update_type(To *ptr);
 
   // No assignment or retrieval functions are declared in PointerToBase,
   // because we will have to specialize on const vs.  non-const later.
 
+  // This is needed to be able to access the privates of other instantiations.
+  template<typename Y> friend class PointerToBase;
+
 PUBLISHED:
   ALWAYS_INLINE void clear();