Created
August 30, 2012 13:20
-
-
Save biochimia/3528409 to your computer and use it in GitHub Desktop.
Proof-of-concept alternative architecture for QObject
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "object.h" | |
#include "one.h" | |
#include "other.h" | |
#include <assert.h> | |
#include <stdio.h> | |
int main() | |
{ | |
Object obj; | |
assert(!obj); | |
obj = Object(42u); | |
assert(obj); | |
assert(42u == obj.getData()); | |
obj.setData(24u); | |
assert(obj); | |
assert(24u == obj.getData()); | |
printf("[%s:%i] ", __FILE__, __LINE__); obj.message(); | |
obj = One(); | |
assert(obj); | |
assert(0 == obj.getData()); | |
printf("[%s:%i] ", __FILE__, __LINE__); obj.message(); | |
printf("[%s:%i] ", __FILE__, __LINE__); static_cast<One &>(obj).oneApi(); | |
obj = Object(); | |
assert(!obj); | |
obj = Other(); | |
assert(obj); | |
assert(0 == static_cast<Other &>(obj).getOtherData()); | |
assert(0 == obj.getData()); | |
obj.setData(37u); | |
assert(0 == static_cast<Other &>(obj).getOtherData()); | |
assert(37u == obj.getData()); | |
static_cast<Other &>(obj).setOtherData(143u); | |
assert(143u == static_cast<Other &>(obj).getOtherData()); | |
assert(37u == obj.getData()); | |
printf("[%s:%i] ", __FILE__, __LINE__); obj.message(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "object_p.h" | |
#include <stdio.h> | |
#include <string.h> | |
ObjectPrivate::~ObjectPrivate() | |
{ | |
printf("%s:%i - %s - ObjectPrivate::~ObjectPrivate()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
ObjectInterface::~ObjectInterface() | |
{ | |
toObjectPrivate(this)->~ObjectPrivate(); | |
} | |
void ObjectInterface::message() const | |
{ | |
printf("%s:%i - %s - ObjectInterface::message()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
Object::Object(uintptr_t data) | |
: ObjectBase(new ObjectPrivateImpl<>) | |
{ | |
setData(data); | |
} | |
void Object::setData(uintptr_t data) | |
{ | |
toObjectPrivate(d)->userData = data; | |
} | |
uintptr_t Object::getData() const | |
{ | |
return toObjectPrivate(d)->userData; | |
} | |
Object::Object(ObjectInterface const &interface) | |
: ObjectBase(new ObjectPrivateImpl<>) | |
{ | |
// Overwrite vtable | |
memcpy((void *)d, (void *)&interface, sizeof(void *)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _OBJECT_H_INCLUDED_ | |
#define _OBJECT_H_INCLUDED_ | |
#include "objectbase.h" | |
#include <type_traits> | |
#include <stdint.h> | |
struct ObjectInterface | |
: InterfaceBase | |
{ | |
virtual ~ObjectInterface(); | |
virtual void message() const; | |
}; | |
static_assert(sizeof(InterfaceBase) == sizeof(ObjectInterface), | |
"ObjectInterface should hold no data!"); | |
struct Object | |
: ObjectBase | |
{ | |
Object() { } | |
explicit Object(uintptr_t userData); | |
void setData(uintptr_t); | |
uintptr_t getData() const; | |
void message() const { d_func()->message(); } | |
private: | |
template <class T> | |
struct Enabler | |
: std::enable_if<std::is_base_of<Object, T>::value> | |
{ | |
}; | |
public: | |
template <class T> | |
Object(T const &other, typename Enabler<T>::type * = 0) | |
: ObjectBase(static_cast<Object const &>(other)) | |
{ | |
validate_<T>(); | |
} | |
template <class T> | |
Object(T &&other, typename Enabler<T>::type * = 0) | |
: ObjectBase(static_cast<Object &&>(other)) | |
{ | |
validate_<T>(); | |
} | |
private: | |
template <class T> | |
static void validate_(typename Enabler<T>::type * = 0) | |
{ | |
static_assert(!std::is_polymorphic<T>::value, | |
"Object hierarchy may not be polymorphic!"); | |
static_assert(sizeof(T) == sizeof(Object), "Slicing will occur!"); | |
} | |
protected: | |
Object(ObjectInterface *interface) : ObjectBase(interface) { } | |
Object(ObjectInterface const &); | |
template <class Interface> | |
Object(Interface const &iface, | |
typename std::enable_if< | |
std::is_base_of<ObjectInterface, Interface>::value | |
&& (sizeof(ObjectInterface) == sizeof(Interface)) | |
>::type * = 0) | |
: Object(static_cast<ObjectInterface const &>(iface)) | |
{ | |
} | |
ObjectInterface *d_func() { return static_cast<ObjectInterface *>(d); } | |
ObjectInterface const *d_func() const { return static_cast<ObjectInterface const *>(d); } | |
}; | |
static_assert(!std::is_polymorphic<Object>::value, | |
"Object must not have a vtable!"); | |
static_assert(sizeof(Object) == sizeof(ObjectBase), | |
"Object should hold no additional data!"); | |
#endif // include guard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _OBJECT_P_H_INCLUDED_ | |
#define _OBJECT_P_H_INCLUDED_ | |
#include "object.h" | |
#include <type_traits> | |
#include <stdint.h> | |
struct ObjectPrivate | |
{ | |
ObjectPrivate() : userData() { } | |
~ObjectPrivate(); | |
uintptr_t userData; | |
}; | |
static_assert(!std::is_polymorphic<ObjectPrivate>::value, | |
"ObjectPrivate should not have a vtable of its own."); | |
template <class Interface = ObjectInterface, class Dummy = void> struct ObjectPrivateImpl; | |
template <class Interface> | |
struct ObjectPrivateImpl<Interface, | |
typename std::enable_if< | |
std::is_base_of<ObjectInterface, Interface>::value | |
&& (sizeof(ObjectInterface) == sizeof(Interface))>::type> | |
: Interface | |
{ | |
ObjectPrivate privateData; | |
}; | |
static inline ObjectPrivate *toObjectPrivate(InterfaceBase *interface) | |
{ | |
return &static_cast<ObjectPrivateImpl<> *>(interface)->privateData; | |
} | |
static inline ObjectPrivate const *toObjectPrivate(InterfaceBase const *interface) | |
{ | |
return &static_cast<ObjectPrivateImpl<> const *>(interface)->privateData; | |
} | |
#endif // include guard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _OBJECTBASE_H_INCLUDED_ | |
#define _OBJECTBASE_H_INCLUDED_ | |
#include <atomic> | |
#include <type_traits> | |
#include <stdint.h> | |
/*! | |
* \brief A ref-counted virtual table, the base class for all Interfaces | |
*/ | |
struct InterfaceBase | |
{ | |
InterfaceBase() : refCount(1) { } | |
virtual ~InterfaceBase() { } | |
void ref() | |
{ | |
refCount.fetch_add(1, std::memory_order_acquire); | |
} | |
bool deref() | |
{ | |
return 1 == refCount.fetch_sub(1, std::memory_order_release); | |
} | |
bool isShared() const | |
{ | |
return refCount.load(std::memory_order_relaxed) > 1; | |
} | |
private: | |
std::atomic<uintptr_t> refCount; | |
}; | |
static_assert(std::is_polymorphic<InterfaceBase>::value, | |
"InterfaceBase missing virtual destructor!"); | |
static_assert(sizeof(std::atomic<uintptr_t>) == sizeof(void *), | |
"This is rather unexpected!"); | |
static_assert(sizeof(InterfaceBase) == 2 * sizeof(void *), | |
"InterfaceBase should be pointer to vtable + reference count!"); | |
struct ObjectBase | |
{ | |
ObjectBase() : d() { } | |
ObjectBase(ObjectBase const &other) | |
: d(other.d ? (other.d->ref(), other.d) : 0) | |
{ | |
} | |
ObjectBase(ObjectBase &&other) | |
: d(other.d) | |
{ | |
other.d = 0; | |
} | |
~ObjectBase() | |
{ | |
if (d && d->deref()) | |
delete d; | |
} | |
ObjectBase &operator=(ObjectBase other) | |
{ | |
std::swap(other.d, d); | |
return *this; | |
} | |
typedef bool (ObjectBase::*Bool) () const; | |
bool isValid() const { return d; } | |
operator Bool() const { return d ? &ObjectBase::isValid : 0; } | |
bool isShared() const { return d->isShared(); } | |
bool isSharedWith(ObjectBase const &other) const { return d == other.d; } | |
protected: | |
ObjectBase(InterfaceBase *interface) : d(interface) { } | |
InterfaceBase *d; | |
}; | |
static_assert(!std::is_polymorphic<ObjectBase>::value, | |
"ObjectBase must not have a vtable!"); | |
static_assert(sizeof(ObjectBase) == sizeof(InterfaceBase *), | |
"ObjectBase should hold only a pointer to InterfaceBase!"); | |
#endif // include guard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "one.h" | |
#include <stdio.h> | |
OneInterface::~OneInterface() | |
{ | |
printf("%s:%i - %s - OneInterface::~OneInterface()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
void OneInterface::message() const | |
{ | |
printf("%s:%i - %s - OneInterface::message()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
void OneInterface::oneApi() const | |
{ | |
printf("%s:%i - %s - OneInterface::oneApi()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
One::One() | |
: Object(OneInterface()) | |
{ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _ONE_H_INCLUDED_ | |
#define _ONE_H_INCLUDED_ | |
#include "object.h" | |
struct OneInterface | |
: ObjectInterface | |
{ | |
~OneInterface() override; | |
void message() const override; | |
virtual void oneApi() const; | |
}; | |
struct One | |
: Object | |
{ | |
One(); | |
void oneApi() const { return d_func()->oneApi(); } | |
private: | |
OneInterface *d_func() { return static_cast<OneInterface *>(d); } | |
OneInterface const *d_func() const { return static_cast<OneInterface const *>(d); } | |
}; | |
#endif // include guard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "other.h" | |
#include "object_p.h" | |
#include <stdio.h> | |
struct OtherPrivate | |
{ | |
OtherPrivate() : data() { } | |
~OtherPrivate() | |
{ | |
printf("%s:%i - %s - OtherPrivate::~OtherPrivate()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
uintptr_t data; | |
}; | |
struct OtherPrivateImpl | |
: ObjectPrivateImpl<OtherInterface> | |
{ | |
OtherPrivate privateData; | |
}; | |
static inline OtherPrivate *toOtherPrivate(InterfaceBase *interface) | |
{ | |
return &static_cast<OtherPrivateImpl *>(interface)->privateData; | |
} | |
static inline OtherPrivate const *toOtherPrivate(InterfaceBase const *interface) | |
{ | |
return &static_cast<OtherPrivateImpl const *>(interface)->privateData; | |
} | |
OtherInterface::~OtherInterface() | |
{ | |
printf("%s:%i - %s - OtherInterface::~OtherInterface()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
void OtherInterface::message() const | |
{ | |
printf("%s:%i - %s - OtherInterface::message()\n", | |
__FILE__, __LINE__, __func__); | |
} | |
Other::Other() | |
: Object(new OtherPrivateImpl) | |
{ | |
} | |
void Other::setOtherData(uintptr_t data) | |
{ | |
toOtherPrivate(d)->data = data; | |
} | |
uintptr_t Other::getOtherData() const | |
{ | |
return toOtherPrivate(d)->data; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _OTHER_H_INCLUDED_ | |
#define _OTHER_H_INCLUDED_ | |
#include "object.h" | |
struct OtherInterface | |
: ObjectInterface | |
{ | |
~OtherInterface() override; | |
void message() const override; | |
}; | |
struct Other | |
: Object | |
{ | |
Other(); | |
void setOtherData(uintptr_t data); | |
uintptr_t getOtherData() const; | |
}; | |
#endif // include guard |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment