Added DynamicQObjectFactory methods to C interface

This commit is contained in:
Filippo Cucchetto 2015-12-27 17:58:49 +01:00
parent 83893b2934
commit 711131b4f4
14 changed files with 284 additions and 53 deletions

View File

@ -16,6 +16,7 @@ find_package(Qt5Widgets)
set(HEADERS_LIST
include/DOtherSide/BaseQAbstractListModel.h
include/DOtherSide/DOtherSideTypes.h
include/DOtherSide/DOtherSideTypesCpp.h
include/DOtherSide/DynamicSignal.h
include/DOtherSide/BaseQObject.h
include/DOtherSide/DynamicProperty.h
@ -26,6 +27,7 @@ set(HEADERS_LIST
include/DOtherSide/OnSlotExecutedHandler.h
include/DOtherSide/DynamicQObjectFactory.h
include/DOtherSide/DynamicQObject2.h
include/DOtherSide/Utils.h
)
set(SRC_LIST
@ -36,6 +38,7 @@ set(SRC_LIST
src/DynamicProperty.cpp
src/DynamicQObjectFactory.cpp
src/DynamicQObject2.cpp
src/DOtherSideTypesCpp.cpp
)
include_directories(include include/Qt)

View File

@ -169,6 +169,17 @@ DOS_API void dos_qurl_create(void** vptr, const char* url, int parsingMode);
DOS_API void dos_qurl_delete(void* vptr);
DOS_API void dos_qurl_to_string(void* vptr, char** result);
// QObjectFactory
DOS_API void dos_qobjectfactory_create(void** vptr,
SignalDefinitions signalDefinitions,
SlotDefinitions slotDefinitions,
PropertyDefinitions propertyDefinitions);
DOS_API void dos_qobjectfactory_delete(void* vptr);
DOS_API void dos_qobjectfactory_create_qobject(void* vptr,
void* dObjectPointer,
DObjectCallback dObjectCallback,
void** result);
#ifdef __cplusplus
}
#endif

View File

@ -30,8 +30,50 @@ typedef void(*RoleNamesCallback)(void* model, QHashIntQByteArrayVoidPtr result);
typedef void(*FlagsCallback) (void* model, QModelIndexVoidPtr index, IntPtr result);
typedef void(*HeaderDataCallback) (void* model, int section, int orientation, int role, QVariantVoidPtr result);
struct SignalDefinition
{
const char* name;
int parametersCount;
int* parametersMetaTypes;
};
struct SignalDefinitions
{
int count;
SignalDefinition* definitions;
};
struct SlotDefinition
{
const char* name;
int returnMetaType;
int parametersCount;
int* parametersMetaTypes;
};
struct SlotDefinitions
{
int count;
SlotDefinition* definitions;
};
struct PropertyDefinition
{
const char* name;
int propertyMetaType;
const char* readSlot;
const char* writeSlot;
const char* notifySignal;
};
struct PropertyDefinitions
{
int count;
PropertyDefinition* definitions;
};
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@ -0,0 +1,92 @@
#pragma once
#include <QtCore/QString>
#include <QtCore/QMetaType>
#include "DOtherSide/DOtherSideTypes.h"
#include "DOtherSide/Utils.h"
namespace DOS
{
struct SignalDefinition
{
SignalDefinition(QString n,
std::vector<QMetaType::Type> v)
: name(std::move(n))
, parameterTypes(std::move(v))
{}
SignalDefinition(::SignalDefinition cType)
: name(QString::fromUtf8(cType.name))
{
auto wrapped = wrap_array(cType.parametersMetaTypes, cType.parametersCount);
auto conversion = [](int type)->QMetaType::Type { return static_cast<QMetaType::Type>(type);};
std::transform(wrapped.begin(), wrapped.end(), parameterTypes.begin(), conversion);
}
QString name;
std::vector<QMetaType::Type> parameterTypes;
};
struct SlotDefinition
{
SlotDefinition(QString n,
QMetaType::Type t,
std::vector<QMetaType::Type> v)
: name(std::move(n))
, returnType(std::move(t))
, parameterTypes(std::move(v))
{}
SlotDefinition(::SlotDefinition cType)
: name(QString::fromUtf8(cType.name))
, returnType(static_cast<QMetaType::Type>(cType.returnMetaType))
{
auto wrapped = wrap_array(cType.parametersMetaTypes, cType.parametersCount);
auto conversion = [](int type)->QMetaType::Type { return static_cast<QMetaType::Type>(type);};
std::transform(wrapped.begin(), wrapped.end(), parameterTypes.begin(), conversion);
}
QString name;
QMetaType::Type returnType;
std::vector<QMetaType::Type> parameterTypes;
};
struct PropertyDefinition
{
PropertyDefinition(QString n,
QMetaType::Type t,
QString r,
QString w,
QString s)
: name(std::move(n))
, type(std::move(t))
, readSlot(std::move(r))
, writeSlot(std::move(w))
, notifySignal(std::move(s))
{}
PropertyDefinition(::PropertyDefinition cType)
: name(cType.name)
, type(static_cast<QMetaType::Type>(cType.propertyMetaType))
, readSlot(QString::fromUtf8(cType.readSlot))
, writeSlot(QString::fromUtf8(cType.writeSlot))
, notifySignal(QString::fromUtf8(cType.notifySignal))
{}
QString name;
QMetaType::Type type;
QString readSlot;
QString writeSlot;
QString notifySignal;
};
using SignalDefinitions = std::vector<SignalDefinition>;
using SlotDefinitions = std::vector<SlotDefinition>;
using PropertyDefinitions = std::vector<PropertyDefinition>;
SignalDefinitions toVector(const ::SignalDefinitions& cType);
SlotDefinitions toVector(const ::SlotDefinitions& cType);
PropertyDefinitions toVector(const ::PropertyDefinitions& cType);
}

View File

@ -3,12 +3,15 @@
#include <QObject>
#include <functional>
namespace DOS
{
class DynamicQObjectFactory;
class DynamicQObject2 : public QObject
{
public:
using OnSlotExecuted = std::function<QVariant(int, const QString&, const std::vector<QVariant>&)>;
using OnSlotExecuted = std::function<QVariant(const QString&, const std::vector<QVariant>&)>;
DynamicQObject2(const DynamicQObjectFactory* factory,
OnSlotExecuted handler);
@ -25,3 +28,5 @@ private:
const DynamicQObjectFactory* const m_factory;
const OnSlotExecuted m_handler;
};
} // namespace DOS

View File

@ -3,48 +3,28 @@
#include <memory>
#include <unordered_map>
#include <tuple>
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QHash>
struct SignalDefinition
{
QString name;
std::vector<QMetaType::Type> argumentsTypes;
};
#include "DOtherSide/DOtherSideTypesCpp.h"
struct SlotDefinition
namespace DOS
{
QString name;
QMetaType::Type returnType;
std::vector<QMetaType::Type> argumentsTypes;
};
struct PropertyDefinition
{
QString name;
QMetaType::Type type;
QString readSlot;
QString writeSlot;
QString notifySignal;
};
class DynamicQObject2;
class DynamicQObjectFactory
{
using SignalDefinitions = std::vector<SignalDefinition>;
using SlotDefinitions = std::vector<SlotDefinition>;
using PropertyDefinitions = std::vector<PropertyDefinition>;
using SafeQMetaObjectPtr = std::unique_ptr<QMetaObject, void(*)(void*)>;
using OnSlotExecuted = std::function<QVariant(int, const QString&, const std::vector<QVariant>&)>;
using OnSlotExecuted = std::function<QVariant(const QString&, const std::vector<QVariant>&)>;
public:
DynamicQObjectFactory(SignalDefinitions signalDefinitions,
SlotDefinitions slotDefinitions,
PropertyDefinitions propertyDefinitions);
DynamicQObject2* create(OnSlotExecuted handler) const;
inline const QMetaObject* metaObject() const;
inline int signalSlotIndex(const QString& signalName) const;
@ -76,3 +56,5 @@ inline int DynamicQObjectFactory::writeSlotIndex(const char *propertyName) const
{
return m_propertySlots.value(propertyName, {-1,-1}).second;
}
} // namespace DOS

View File

@ -14,7 +14,8 @@ class OnSlotExecutedHandler
public:
OnSlotExecutedHandler(void* dObjectPointer, IDynamicQObject::Callback dObjectCallback);
QVariant operator()(const DynamicSlot& slot, std::vector<QVariant> const& args);
QVariant operator()(const QString& name, const std::vector<QVariant>& args);
QVariant operator()(const DynamicSlot& slot, const std::vector<QVariant>& args);
private:
void* m_dObjectPointer;

View File

@ -0,0 +1,32 @@
#pragma once
#include <algorithm>
namespace DOS
{
template <typename T>
struct wrapped_array {
wrapped_array(T* first, T* last) : begin_ {first}, end_ {last} {}
wrapped_array(T* first, std::ptrdiff_t size)
: wrapped_array {first, first + size} {}
T* begin() const noexcept { return begin_; }
T* end() const noexcept { return end_; }
T* begin_;
T* end_;
};
template <typename T>
wrapped_array<T> wrap_array(T* first, std::ptrdiff_t size) noexcept
{ return {first, size}; }
template <typename T, typename G>
std::vector<T> toVector(const wrapped_array<G>& array)
{
std::vector<T> result;
std::copy(array.begin(), array.end(), result.begin());
return result;
}
}

View File

@ -13,10 +13,14 @@
#include <QtQuick/QQuickView>
#include <QtWidgets/QApplication>
#include "DOtherSide/DOtherSideTypesCpp.h"
#include "DOtherSide/DynamicQObject.h"
#include "DOtherSide/BaseQAbstractListModel.h"
#include "DOtherSide/BaseQObject.h"
#include "DOtherSide/OnSlotExecutedHandler.h"
#include "DOtherSide/DynamicQObjectFactory.h"
#include "DOtherSide/DynamicQObject2.h"
void convert_to_cstring(const QString& source, char** destination)
{
@ -649,3 +653,25 @@ void dos_qurl_to_string(void* vptr, char** result)
convert_to_cstring(url->toString(), result);
}
void dos_qobjectfactory_create(void **vptr,
SignalDefinitions signalDefinitions,
SlotDefinitions slotDefinitions,
PropertyDefinitions propertyDefinitions)
{
*vptr = new DOS::DynamicQObjectFactory(DOS::toVector(signalDefinitions),
DOS::toVector(slotDefinitions),
DOS::toVector(propertyDefinitions));
}
void dos_qobjectfactory_delete(void *vptr)
{
auto factory = reinterpret_cast<DOS::DynamicQObjectFactory*>(vptr);
delete factory;
}
void dos_qobjectfactory_create_qobject(void *vptr, void* dObjectPointer, DObjectCallback dObjectCallback, void **result)
{
auto factory = reinterpret_cast<DOS::DynamicQObjectFactory*>(vptr);
*result = factory->create(OnSlotExecutedHandler(dObjectPointer, dObjectCallback));
}

View File

@ -0,0 +1,19 @@
#include "DOtherSide/DOtherSideTypesCpp.h"
namespace DOS {
SignalDefinitions toVector(const ::SignalDefinitions& cType)
{
return toVector<SignalDefinition, ::SignalDefinition>(wrap_array(cType.definitions, cType.count));
}
SlotDefinitions toVector(const ::SlotDefinitions& cType)
{
return toVector<SlotDefinition, ::SlotDefinition>(wrap_array(cType.definitions, cType.count));
}
PropertyDefinitions toVector(const ::PropertyDefinitions& cType)
{
return toVector<PropertyDefinition, ::PropertyDefinition>(wrap_array(cType.definitions, cType.count));
}
}

View File

@ -3,6 +3,9 @@
#include <QtCore/QMetaMethod>
#include <QtCore/QDebug>
namespace DOS
{
DynamicQObject2::DynamicQObject2(const DynamicQObjectFactory *factory,
OnSlotExecuted handler)
: m_factory(factory)
@ -63,7 +66,7 @@ bool DynamicQObject2::executeSlot(int index, void **args)
arguments.emplace_back(std::move(argument));
}
QVariant result = m_handler(index, method.name(), arguments); // Execute method
QVariant result = m_handler(method.name(), arguments); // Execute method
if (method.returnType() != QMetaType::Void && result.isValid()) {
QMetaType::construct(method.returnType(), args[0], result.constData());
@ -91,3 +94,5 @@ bool DynamicQObject2::writeProperty(int index, void **args)
}
return executeSlot(m_factory->writeSlotIndex(property.name()), args);
}
} // namespace DOS

View File

@ -6,23 +6,28 @@
namespace
{
template<class T>
QByteArray createSignature(const T& functionDefinition)
{
QString signature("%1(%2)");
QString arguments;
template<class T>
QByteArray createSignature(const T& functionDefinition)
{
QString signature("%1(%2)");
QString arguments;
for (QMetaType::Type type : functionDefinition.argumentsTypes) {
if (type != functionDefinition.argumentsTypes.front())
arguments += QLatin1Char(',');
arguments += QMetaType::typeName(type);
}
return signature.arg(functionDefinition.name, arguments).toUtf8();
for (int type : functionDefinition.parameterTypes) {
if (type != functionDefinition.parameterTypes.front())
arguments += QLatin1Char(',');
arguments += QMetaType::typeName(type);
}
return signature.arg(functionDefinition.name, arguments).toUtf8();
}
}
DynamicQObjectFactory::DynamicQObjectFactory(DynamicQObjectFactory::SignalDefinitions signalDefinitions, DynamicQObjectFactory::SlotDefinitions slotDefinitions, DynamicQObjectFactory::PropertyDefinitions propertyDefinitions)
namespace DOS
{
DynamicQObjectFactory::DynamicQObjectFactory(SignalDefinitions signalDefinitions,
SlotDefinitions slotDefinitions,
PropertyDefinitions propertyDefinitions)
: m_metaObject(nullptr, ::free)
{
QMetaObjectBuilder builder;
@ -34,7 +39,7 @@ DynamicQObjectFactory::DynamicQObjectFactory(DynamicQObjectFactory::SignalDefini
for (const SignalDefinition& signal : signalDefinitions)
{
QMetaMethodBuilder signalBuilder = builder.addSignal(createSignature(signal));
QMetaMethodBuilder signalBuilder = builder.addSignal(::createSignature(signal));
signalBuilder.setReturnType(QMetaType::typeName(QMetaType::Void));
signalBuilder.setAccess(QMetaMethod::Public);
m_signalIndexByName[signal.name.toUtf8()] = signalBuilder.index();
@ -43,7 +48,7 @@ DynamicQObjectFactory::DynamicQObjectFactory(DynamicQObjectFactory::SignalDefini
QHash<QString, int> methodIndexByName;
for (const SlotDefinition& slot : slotDefinitions)
{
QMetaMethodBuilder methodBuilder = builder.addSlot(createSignature(slot));
QMetaMethodBuilder methodBuilder = builder.addSlot(::createSignature(slot));
methodBuilder.setReturnType(QMetaType::typeName(slot.returnType));
methodBuilder.setAttributes(QMetaMethod::Scriptable);
methodIndexByName[slot.name] = methodBuilder.index();
@ -68,3 +73,5 @@ DynamicQObject2* DynamicQObjectFactory::create(OnSlotExecuted handler) const
{
return new DynamicQObject2(this, std::move(handler));
}
} // namespace DOS

View File

@ -7,7 +7,7 @@ OnSlotExecutedHandler::OnSlotExecutedHandler(void *dObjectPointer,
, m_dObjectCallback(dObjectCallback)
{}
QVariant OnSlotExecutedHandler::operator()(const DynamicSlot& slot, const std::vector<QVariant> &args)
QVariant OnSlotExecutedHandler::operator()(const QString &name, const std::vector<QVariant> &args)
{
QVariant result;
@ -15,7 +15,7 @@ QVariant OnSlotExecutedHandler::operator()(const DynamicSlot& slot, const std::v
return result;
// prepare slot name
QVariant slotName(slot.name());
QVariant slotName(name);
// prepare void* for the QVariants
std::vector<void*> argumentsAsVoidPointers;
@ -29,3 +29,8 @@ QVariant OnSlotExecutedHandler::operator()(const DynamicSlot& slot, const std::v
return result;
}
QVariant OnSlotExecutedHandler::operator()(const DynamicSlot& slot, const std::vector<QVariant> &args)
{
return operator ()(slot.name(), args);
}

View File

@ -100,21 +100,22 @@ private slots:
}
void benchmarkDynamicQObject2Performance() {
QBENCHMARK {
DynamicQObjectFactory factory {{SignalDefinition{"fooChanged", {QMetaType::Int}}},
{SlotDefinition{"foo", QMetaType::Int, {}}, SlotDefinition{"setFoo", QMetaType::Void, {QMetaType::Int}}},
{PropertyDefinition{"foo", QMetaType::Int, "foo", "setFoo", "fooChanged"}}};
DOS::DynamicQObjectFactory factory {{DOS::SignalDefinition{"fooChanged", {QMetaType::Int}}},
{DOS::SlotDefinition{"foo", QMetaType::Int, {}}, DOS::SlotDefinition{"setFoo", QMetaType::Void, {QMetaType::Int}}},
{DOS::PropertyDefinition{"foo", QMetaType::Int, "foo", "setFoo", "fooChanged"}}};
for (int i = 0; i < 1000; ++i) {
std::unique_ptr<DynamicQObject2> dynamicQObject(factory.create([](int, const QString&, const std::vector<QVariant>&)-> QVariant{}));
std::unique_ptr<DOS::DynamicQObject2> dynamicQObject(factory.create([](const QString&, const std::vector<QVariant>&)-> QVariant{}));
}
}
}
void testDynamicQObject2() {
DynamicQObjectFactory factory {{SignalDefinition{"fooChanged", {QMetaType::Int}}},
{SlotDefinition{"foo", QMetaType::Int, {}}, SlotDefinition{"setFoo", QMetaType::Void, {QMetaType::Int}}},
{PropertyDefinition{"foo", QMetaType::Int, "foo", "setFoo", "fooChanged"}}};
std::unique_ptr<DynamicQObject2> dynamicQObject(factory.create([](int, const QString&, const std::vector<QVariant>&)-> QVariant{}));
DOS::DynamicQObjectFactory factory {{DOS::SignalDefinition{"fooChanged", {QMetaType::Int}}},
{DOS::SlotDefinition{"foo", QMetaType::Int, {}}, DOS::SlotDefinition{"setFoo", QMetaType::Void, {QMetaType::Int}}},
{DOS::PropertyDefinition{"foo", QMetaType::Int, "foo", "setFoo", "fooChanged"}}};
std::unique_ptr<DOS::DynamicQObject2> dynamicQObject(factory.create([](const QString&, const std::vector<QVariant>&)-> QVariant{}));
QVERIFY(dynamicQObject != nullptr);
QSignalSpy signalSpy(dynamicQObject.get(), SIGNAL(fooChanged(int)));