Skip to content

Instantly share code, notes, and snippets.

@biochimia
Created August 30, 2012 13:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save biochimia/3528409 to your computer and use it in GitHub Desktop.
Save biochimia/3528409 to your computer and use it in GitHub Desktop.
Proof-of-concept alternative architecture for QObject
#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();
}
#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 *));
}
#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
#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
#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
#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())
{
}
#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
#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;
}
#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