Interfaces.h
// Interfaces.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007
@import "cxObject.h"
@import "TypeTraits.h"
@import "TypeOps.h"
namespace ceda
{
class xostream;
struct IObject;
struct ReflectedClass;
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Note that NullInterface, AnyInterface, AnyConstInterface each provide implicit conversions to
either const void* or void*.
Therefore the following operators
* comparison == != < <= > >=
* boolean conversion, allowing for expressions like
if (p) ...
if (!p) ...
are supported uniformly on
T* (for any T)
NullInterface
AnyInterface
AnyConstInterface
ptr<T> (for any T)
ptr<const T> (for any T)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////
// NullInterface
struct NullInterface
{
// Needed to allow default initialisation of an object of const type
// See : http://stackoverflow.com/questions/4674332/declaring-a-const-instance-of-a-class
NullInterface() {}
operator const void*() const { return nullptr; }
};
const NullInterface null;
///////////////////////////////////////////////////////////////////////////////////////////////////
// AnyInterface
typedef void (*FunctionPointer)();
$struct+ AnyInterface
{
AnyInterface() : m_self(nullptr), m_table(nullptr) {}
AnyInterface(NullInterface) : m_self(nullptr), m_table(nullptr) {}
AnyInterface(std::nullptr_t) : m_self(nullptr), m_table(nullptr) {}
AnyInterface(void* self, const FunctionPointer* table) : m_self(self), m_table(table) {}
// With implicit conversion to void* clients get
// 1) == != < <= > >= over T* and ptr<T> for any T
// 2) boolean conversions.
operator void*() const { return m_self; }
$void* self() const { return m_self; }
void* m_self;
const FunctionPointer* m_table;
};
$struct+ AnyConstInterface
{
AnyConstInterface() : m_self(nullptr), m_table(nullptr) {}
AnyConstInterface(AnyInterface v) : m_self(v.m_self), m_table(v.m_table) {}
AnyConstInterface(NullInterface) : m_self(nullptr), m_table(nullptr) {}
AnyConstInterface(std::nullptr_t) : m_self(nullptr), m_table(nullptr) {}
AnyConstInterface(const void* self, const FunctionPointer* table) : m_self(self), m_table(table) {}
// With implicit conversion to void* clients get
// 1) == != < <= > >= over T* and ptr<T> for any T
// 2) boolean conversions.
operator const void*() const { return m_self; }
$const void* self() const { return m_self; }
const void* m_self;
const FunctionPointer* m_table;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// ptr<T>
template <typename T>
struct ptr : public AnyInterface
{
ptr() {}
ptr(NullInterface) {}
ptr(std::nullptr_t) {}
ptr(void* self, const FunctionPointer* table) : AnyInterface(self,table) {}
~ptr() {} // becomes non-POD and thus works in python marshalling
template <typename P>
ptr(P* rhs)
{
// According to the standard, reinterpret_cast<> is not allowed to cast away const-ness. This makes it
// useful for testing const-compatibility!
(void) reinterpret_cast<T*>( (P*) 0 );
((T*)(this))->CoerceFrom(rhs);
}
template <typename B>
ptr(const ptr<B>& rhs)
{
// According to the standard, reinterpret_cast<> is not allowed to cast away const-ness. This makes it
// useful for testing const-compatibility!
(void) reinterpret_cast<T*>( (B*) 0 );
((T*)(this))->AssignFrom(*rhs);
}
T& operator*() const { return (T&)(*this); }
T* operator->() const { return (T*)(this); }
};
template <typename T>
struct ptr<const T> : public AnyConstInterface
{
ptr() {}
ptr(NullInterface) {}
ptr(std::nullptr_t) {}
ptr(const void* self, const FunctionPointer* table) : AnyConstInterface(self,table) {}
~ptr() {} // becomes non-POD and thus works in python marshalling
template <typename P>
ptr(P* rhs) { ((const T*)(this))->CoerceFrom(rhs); }
template <typename B>
ptr(const ptr<B>& rhs) { ((const T*)(this))->AssignFrom(*rhs); }
const T& operator*() const { return (const T&)(*this); }
const T* operator->() const { return (const T*)(this); }
};
template <typename T>
ptr<T> const_interface_cast(ptr<const T> x)
{
return ptr<T>(const_cast<void*>(x.m_self), x.m_table);
}
@api void WriteIObjectPtr(xostream& os, ptr<const IObject> p);
// Note that this assumes that ptr<T> is used with interface T that inherits from IObject
template <typename T>
xostream& operator<<(xostream& os, ptr<T> p)
{
if constexpr (is_superinterface_of<IObject,T>::value)
{
WriteIObjectPtr(os,p);
}
else
{
os << p.m_self;
}
return os;
}
template <typename T>
ptr<T> make_ptr(void* self, const typename T::FnTable* table)
{
return ptr<T>(self, reinterpret_cast<const FunctionPointer*>(table));
}
template <typename T>
ptr<const T> make_ptr(const void* self, const typename T::FnTable* table)
{
return ptr<const T>(self, reinterpret_cast<const FunctionPointer*>(table));
}
} // namespace ceda