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.
This commit is contained in:
rdb 2018-07-08 21:33:49 +02:00
parent 409231d214
commit 23128e4695
4 changed files with 252 additions and 8 deletions

View File

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

View File

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

View File

@ -44,11 +44,24 @@ 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<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;
}
/**
@ -56,9 +69,11 @@ INLINE PointerToBase<T>::
*/
template<class T>
INLINE PointerToBase<T>::
PointerToBase(PointerToBase<T> &&from) noexcept {
_void_ptr = from._void_ptr;
from._void_ptr = nullptr;
~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.

View File

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