version 2.24.0
New PIParseHelper class
This commit is contained in:
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0)
|
||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||
project(pip)
|
||||
set(pip_MAJOR 2)
|
||||
set(pip_MINOR 23)
|
||||
set(pip_REVISION 2)
|
||||
set(pip_MINOR 24)
|
||||
set(pip_REVISION 0)
|
||||
set(pip_SUFFIX )
|
||||
set(pip_COMPANY SHS)
|
||||
set(pip_DOMAIN org.SHS)
|
||||
|
||||
91
doc/examples/piparsehelper.cpp
Normal file
91
doc/examples/piparsehelper.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "pip.h"
|
||||
|
||||
//! [0]
|
||||
enum Header {
|
||||
hInt = 1,
|
||||
hString,
|
||||
hVoid
|
||||
};
|
||||
|
||||
class MyObj: public PIObject, public PIParseHelper<uchar> {
|
||||
PIOBJECT(MyObj);
|
||||
public:
|
||||
MyObj(): PIParseHelper<uchar>(this) {
|
||||
// Keys with 1 argument
|
||||
assign(hInt, std::function<void(int)>([this](int i){piCout << "lambda type Int" << i;}));
|
||||
assign(hInt, HANDLER(methodI));
|
||||
assign(hString, HANDLER(methodS));
|
||||
|
||||
// hVoid key, without arguments
|
||||
assign(hVoid, [](){piCout << "type void";});
|
||||
assign(hVoid, HANDLER(method));
|
||||
}
|
||||
EVENT_HANDLER1(void, methodI, int, i) {piCout << "methodI" << i;}
|
||||
EVENT_HANDLER1(void, methodS, PIString, s) {piCout << "methodS" << s;}
|
||||
EVENT_HANDLER0(void, method) {piCout << "method";}
|
||||
};
|
||||
|
||||
int main() {
|
||||
MyObj o;
|
||||
|
||||
PIByteArray data;
|
||||
|
||||
data.clear();
|
||||
data << 11;
|
||||
o.parse(hInt, data);
|
||||
// lambda type Int 11
|
||||
// methodI 11
|
||||
|
||||
data.clear();
|
||||
data << PIString("text");
|
||||
o.parse(hString, data);
|
||||
// methodS text
|
||||
|
||||
data.clear();
|
||||
o.parse(hVoid, data);
|
||||
// type void
|
||||
// method
|
||||
}
|
||||
//! [0]
|
||||
|
||||
|
||||
//! [1]
|
||||
enum Header {
|
||||
hInt = 1,
|
||||
hString,
|
||||
hVoid
|
||||
};
|
||||
|
||||
class MyObj: public PIObject {
|
||||
PIOBJECT(MyObj);
|
||||
public:
|
||||
EVENT_HANDLER1(void, methodI, int, i) {piCout << "methodI" << i;}
|
||||
EVENT_HANDLER1(void, methodS, PIString, s) {piCout << "methodS" << s;}
|
||||
EVENT_HANDLER0(void, method) {piCout << "method";}
|
||||
};
|
||||
|
||||
int main() {
|
||||
MyObj obj;
|
||||
PIParseHelper<int> parser(&obj);
|
||||
|
||||
parser.assign(hInt, obj.HANDLER(methodI));
|
||||
parser.assign(hString, obj.HANDLER(methodS));
|
||||
parser.assign(hVoid, obj.HANDLER(method));
|
||||
|
||||
PIByteArray data;
|
||||
|
||||
data.clear();
|
||||
data << 11;
|
||||
parser.parse(hInt, data);
|
||||
// methodI 11
|
||||
|
||||
data.clear();
|
||||
data << PIString("text");
|
||||
parser.parse(hString, data);
|
||||
// methodS text
|
||||
|
||||
data.clear();
|
||||
parser.parse(hVoid, data);
|
||||
// method
|
||||
}
|
||||
//! [1]
|
||||
@@ -26,5 +26,6 @@
|
||||
#include "pidiagnostics.h"
|
||||
#include "pifiletransfer.h"
|
||||
#include "pipacketextractor.h"
|
||||
#include "piparsehelper.h"
|
||||
|
||||
#endif // PIIOUTILSMODULE_H
|
||||
|
||||
174
libs/main/io_utils/piparsehelper.h
Normal file
174
libs/main/io_utils/piparsehelper.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*! \file piparsehelper.h
|
||||
* \brief Helper class to automate structs receive
|
||||
*/
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Helper class to automate structs receive
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PIPARSEHELPER_H
|
||||
#define PIPARSEHELPER_H
|
||||
|
||||
#include "pip_io_utils_export.h"
|
||||
#include "piobject.h"
|
||||
|
||||
|
||||
/** \class PIParseHelper
|
||||
* \brief Helper class to automate structs receive
|
||||
*
|
||||
*
|
||||
* \section PIParseHelper_synopsis Synopsis
|
||||
* This class helps to deserialize and invoke neccessarily methods.
|
||||
*
|
||||
* Data packets with header and various data types can be automated by this class.
|
||||
* Every key value mapped to event handler or lambda-function.
|
||||
*
|
||||
* This class can remove \b switch-case with deserialization code and
|
||||
* replace it with several \a assign() calls, binded to ready-to-use event handlers.
|
||||
* Moreover data type automatic takes from event handler or lambda argument. One should
|
||||
* only make \"PIByteArray & operator <<()\" with used types, deserialization will be
|
||||
* performed by %PIParseHelper.
|
||||
*
|
||||
*
|
||||
* \section PIParseHelper_usage Usage
|
||||
* There are two variants: subclassing and aggregating.
|
||||
*
|
||||
* ### Subclass
|
||||
*
|
||||
* Inherit your class from %PIParseHelper and construct it with \b this.
|
||||
*
|
||||
* In \a assign() methods you can use event handlers with 0 or 1 arguments,
|
||||
* using HANDLER() macro.
|
||||
*
|
||||
* ### Aggregate
|
||||
*
|
||||
* Create instance of %PIParseHelper and construct it with target object.
|
||||
*
|
||||
* In \a assign() methods you can use event handlers with 0 or 1 arguments,
|
||||
* using HANDLER() macro in target object namespace (e.g. \"o.HANDLER(slot)\").
|
||||
*
|
||||
*
|
||||
* \section PIParseHelper_lambda Lambda-functions
|
||||
* Assign methods that receive lambda-functions can`t accept direct lambda (\"[](){}\")
|
||||
* with template type deducation because of C++ specific. E.g.
|
||||
* \code assign(1, [this](SomeStruct s){}) \endcode
|
||||
* doesn`t compile, but these variants allowed:
|
||||
* \code assign(1, std::function<void(SomeStruct)>([this](SomeStruct s){})) \endcode
|
||||
* \code assign<SomeStruct>(1, [this](SomeStruct s){}) \endcode
|
||||
*
|
||||
*
|
||||
* \section PIParseHelper_examples Examples
|
||||
* First example describes subclass variant. As one can see, it`s a single place to change
|
||||
* type of received data - event handler argument.
|
||||
* \snippet piparsehelper.cpp 0
|
||||
*
|
||||
* Second example show separate variant:
|
||||
* \snippet piparsehelper.cpp 1
|
||||
*
|
||||
**/
|
||||
|
||||
template <typename Key>
|
||||
class PIParseHelper {
|
||||
public:
|
||||
|
||||
//! \brief Construct %PIParseHelper with target object \"p\"
|
||||
PIParseHelper(PIObject * p): parent(p) {}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to event handler \"handler\" with 1 argument
|
||||
template <typename T, typename Ret>
|
||||
void assign(Key key, Ret(*handler)(void*,T)) {
|
||||
if (!parent) return;
|
||||
auto mf = PIObject::__meta_data().value(parent->classNameID());
|
||||
auto it = mf.eh_func.makeIterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value().addr == handler) {
|
||||
void * addr = it.value().addr;
|
||||
auto func = [addr](PIObject * o, PIByteArray data){
|
||||
T v; data >> v;
|
||||
((void(*)(void*, T))addr)(o, v);
|
||||
};
|
||||
functions[key] << func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to event handler \"handler\" without arguments
|
||||
template <typename Ret>
|
||||
void assign(Key key, Ret(*handler)(void*)) {
|
||||
if (!parent) return;
|
||||
auto mf = PIObject::__meta_data().value(parent->classNameID());
|
||||
auto it = mf.eh_func.makeIterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.value().addr == handler) {
|
||||
void * addr = it.value().addr;
|
||||
auto func = [addr](PIObject * o, PIByteArray ){
|
||||
((void(*)(void*))addr)(o);
|
||||
};
|
||||
functions[key] << func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to lambda-function \"func\" with 1 argument
|
||||
//! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda
|
||||
template <typename T>
|
||||
void assign(Key key, std::function<void(T)> func) {
|
||||
if (!parent) return;
|
||||
auto lf = [func](PIObject * , PIByteArray data){
|
||||
if (!data.isEmpty()) {
|
||||
T v; data >> v;
|
||||
func(v);
|
||||
}
|
||||
};
|
||||
functions[key] << lf;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Assign key \"key\" to lambda-function \"func\" without arguments
|
||||
//! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda
|
||||
void assign(Key key, std::function<void()> func) {
|
||||
if (!parent) return;
|
||||
auto lf = [func](PIObject * , PIByteArray ){
|
||||
func();
|
||||
};
|
||||
functions[key] << lf;
|
||||
}
|
||||
|
||||
|
||||
//! \brief Deserialize data and invoke assigned to \"key\" methods
|
||||
void parse(Key key, PIByteArray ba) {
|
||||
if (!parent) return;
|
||||
auto fl = functions.value(key);
|
||||
for (auto f: fl)
|
||||
f(parent, ba);
|
||||
}
|
||||
|
||||
private:
|
||||
PIMap<Key, PIVector<std::function<void(PIObject *, PIByteArray)>>> functions;
|
||||
PIObject * parent;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // PIPARSEHELPER_H
|
||||
56
main.cpp
56
main.cpp
@@ -1,27 +1,39 @@
|
||||
#include "pip.h"
|
||||
extern "C" {
|
||||
# include "lua.h"
|
||||
# include "lauxlib.h"
|
||||
# include "lualib.h"
|
||||
}
|
||||
#include <LuaBridge/LuaBridge.h>
|
||||
#include "pistring_std.h"
|
||||
enum Header {
|
||||
hInt = 1,
|
||||
hString,
|
||||
hVoid
|
||||
};
|
||||
|
||||
static const char * script
|
||||
= "-- script.lua \n"
|
||||
"testString = \"LuaBridge works!\" \n"
|
||||
"number = 42 \n";
|
||||
class MyObj: public PIObject {
|
||||
PIOBJECT(MyObj);
|
||||
public:
|
||||
EVENT_HANDLER1(void, methodI, int, i) {piCout << "methodI" << i;}
|
||||
EVENT_HANDLER1(void, methodS, PIString, s) {piCout << "methodS" << s;}
|
||||
EVENT_HANDLER0(void, method) {piCout << "method";}
|
||||
};
|
||||
|
||||
using namespace luabridge;
|
||||
int main() {
|
||||
lua_State* L = luaL_newstate();
|
||||
luaL_dostring(L, script);
|
||||
luaL_openlibs(L);
|
||||
lua_pcall(L, 0, 0, 0);
|
||||
LuaRef s = getGlobal(L, "testString");
|
||||
LuaRef n = getGlobal(L, "number");
|
||||
std::string luaString = s.cast<std::string>();
|
||||
int answer = n.cast<int>();
|
||||
piCout << StdString2PIString(luaString);
|
||||
piCout << "And here's our number:" << answer;
|
||||
MyObj o;
|
||||
PIParseHelper<int> parser(&o);
|
||||
|
||||
parser.assign(hInt, o.HANDLER(methodI));
|
||||
parser.assign(hString, o.HANDLER(methodS));
|
||||
parser.assign(hVoid, o.HANDLER(method));
|
||||
|
||||
PIByteArray data;
|
||||
|
||||
data.clear();
|
||||
data << 11;
|
||||
parser.parse(hInt, data);
|
||||
// methodI 11
|
||||
|
||||
data.clear();
|
||||
data << PIString("text");
|
||||
parser.parse(hString, data);
|
||||
// methodS text
|
||||
|
||||
data.clear();
|
||||
parser.parse(hVoid, data);
|
||||
// method
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user