version 4.2.0
move toStdFunction() to pibase.h refactor PIParseHelper, now it much more abstract and useful fix PIIODevice::createFromFullPath() when whitespaces at start or end are presence PIStreamPacker add events for start and end packet receive PIClientServer::ClientBase add virtual methods for start and end packet receive. also one can enable diagnostics with enableDiagnostics() method PICout now call flush() on each end of output add PIString::entries(const PIString & str)
This commit is contained in:
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
|
|||||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||||
project(PIP)
|
project(PIP)
|
||||||
set(PIP_MAJOR 4)
|
set(PIP_MAJOR 4)
|
||||||
set(PIP_MINOR 1)
|
set(PIP_MINOR 2)
|
||||||
set(PIP_REVISION 0)
|
set(PIP_REVISION 0)
|
||||||
set(PIP_SUFFIX )
|
set(PIP_SUFFIX )
|
||||||
set(PIP_COMPANY SHS)
|
set(PIP_COMPANY SHS)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ PIClientServer::ClientBase::~ClientBase() {
|
|||||||
close();
|
close();
|
||||||
stopAndWait();
|
stopAndWait();
|
||||||
if (own_tcp) piDeleteSafety(tcp);
|
if (own_tcp) piDeleteSafety(tcp);
|
||||||
|
piDeleteSafety(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -60,17 +61,38 @@ int PIClientServer::ClientBase::write(const void * d, const size_t s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIClientServer::ClientBase::enableDiagnostics() {
|
||||||
|
if (diag) return;
|
||||||
|
diag = new PIDiagnostics();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIDiagnostics::State PIClientServer::ClientBase::diagnostics() const {
|
||||||
|
if (!diag) return {};
|
||||||
|
return diag->state();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PIClientServer::ClientBase::receivePacketProgress() const {
|
||||||
|
return stream.receivePacketProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIClientServer::ClientBase::init() {
|
void PIClientServer::ClientBase::init() {
|
||||||
if (!tcp) return;
|
if (!tcp) return;
|
||||||
CONNECTL(&stream, sendRequest, [this](const PIByteArray & ba) {
|
CONNECTL(&stream, sendRequest, [this](const PIByteArray & ba) {
|
||||||
if (!can_write) return;
|
if (!can_write) return;
|
||||||
tcp->send(ba);
|
tcp->send(ba);
|
||||||
|
if (diag) diag->sended(ba.size_s());
|
||||||
// piMSleep(1);
|
// piMSleep(1);
|
||||||
});
|
});
|
||||||
CONNECTL(&stream, packetReceiveEvent, [this](PIByteArray & ba) { readed(ba); });
|
CONNECTL(&stream, packetReceiveEvent, [this](PIByteArray & ba) { readed(ba); });
|
||||||
|
CONNECTL(&stream, startPacketReceive, [this](int size) { receivePacketStart(size); });
|
||||||
|
CONNECTL(&stream, endPacketReceive, [this]() { receivePacketEnd(); });
|
||||||
CONNECTL(tcp, threadedReadEvent, [this](const uchar * readed, ssize_t size) {
|
CONNECTL(tcp, threadedReadEvent, [this](const uchar * readed, ssize_t size) {
|
||||||
if (!can_write) return;
|
if (!can_write) return;
|
||||||
stream.received(readed, size);
|
stream.received(readed, size);
|
||||||
|
if (diag) diag->received(size);
|
||||||
});
|
});
|
||||||
CONNECTL(tcp, connected, [this]() {
|
CONNECTL(tcp, connected, [this]() {
|
||||||
can_write = true;
|
can_write = true;
|
||||||
|
|||||||
@@ -167,7 +167,10 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
|||||||
stream.remove(0, hdr_size);
|
stream.remove(0, hdr_size);
|
||||||
packet.clear();
|
packet.clear();
|
||||||
packet_size = sz;
|
packet_size = sz;
|
||||||
if (packet_size == 0) packet_size = -1;
|
if (packet_size == 0)
|
||||||
|
packet_size = -1;
|
||||||
|
else
|
||||||
|
startPacketReceive(packet_size);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
|
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
|
||||||
@@ -196,6 +199,7 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
|||||||
}
|
}
|
||||||
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
|
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
|
||||||
if (!cd.isEmpty()) {
|
if (!cd.isEmpty()) {
|
||||||
|
endPacketReceive();
|
||||||
packetReceived(cd);
|
packetReceived(cd);
|
||||||
packetReceiveEvent(cd);
|
packetReceiveEvent(cd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#define piclientserver_client_base_H
|
#define piclientserver_client_base_H
|
||||||
|
|
||||||
#include "piclientserver_config.h"
|
#include "piclientserver_config.h"
|
||||||
|
#include "pidiagnostics.h"
|
||||||
#include "pip_client_server_export.h"
|
#include "pip_client_server_export.h"
|
||||||
#include "pistreampacker.h"
|
#include "pistreampacker.h"
|
||||||
|
|
||||||
@@ -52,12 +53,18 @@ public:
|
|||||||
int write(const void * d, const size_t s);
|
int write(const void * d, const size_t s);
|
||||||
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
|
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
|
||||||
|
|
||||||
|
void enableDiagnostics();
|
||||||
|
PIDiagnostics::State diagnostics() const;
|
||||||
|
int receivePacketProgress() const;
|
||||||
|
|
||||||
Config & configuration() { return config; }
|
Config & configuration() { return config; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void readed(PIByteArray data) {}
|
virtual void readed(PIByteArray data) {}
|
||||||
virtual void connected() {}
|
virtual void connected() {}
|
||||||
virtual void disconnected() {}
|
virtual void disconnected() {}
|
||||||
|
virtual void receivePacketStart(int size) {}
|
||||||
|
virtual void receivePacketEnd() {}
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
@@ -71,6 +78,7 @@ private:
|
|||||||
|
|
||||||
PIStreamPacker stream;
|
PIStreamPacker stream;
|
||||||
mutable PIMutex write_mutex;
|
mutable PIMutex write_mutex;
|
||||||
|
PIDiagnostics * diag = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace PIClientServer
|
} // namespace PIClientServer
|
||||||
|
|||||||
@@ -720,4 +720,20 @@ struct PIP_EXPORT PINonTriviallyCopyable {
|
|||||||
inline PINonTriviallyCopyable::PINonTriviallyCopyable(PINonTriviallyCopyable &&) noexcept = default;
|
inline PINonTriviallyCopyable::PINonTriviallyCopyable(PINonTriviallyCopyable &&) noexcept = default;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct FunctionType {
|
||||||
|
using Type = void;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Args>
|
||||||
|
struct FunctionType<Ret (Class::*)(Args...) const> {
|
||||||
|
using Type = std::function<Ret(Args...)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
typename FunctionType<decltype(&L::operator())>::Type toStdFunction(L const & func) {
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // PIBASE_H
|
#endif // PIBASE_H
|
||||||
|
|||||||
@@ -159,19 +159,19 @@ DWORD PICout::__Private__::smode = 0;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
std::ostream & getStdStream(PICoutManipulators::PICoutStdStream s) {
|
std::ostream & getStdStream(PICoutStdStream s) {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case PICoutManipulators::StdOut: return std::cout;
|
case PICoutStdStream::StdOut: return std::cout;
|
||||||
case PICoutManipulators::StdErr: return std::cerr;
|
case PICoutStdStream::StdErr: return std::cerr;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
return std::cout;
|
return std::cout;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wostream & getStdWStream(PICoutManipulators::PICoutStdStream s) {
|
std::wostream & getStdWStream(PICoutStdStream s) {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case PICoutManipulators::StdOut: return std::wcout;
|
case PICoutStdStream::StdOut: return std::wcout;
|
||||||
case PICoutManipulators::StdErr: return std::wcerr;
|
case PICoutStdStream::StdErr: return std::wcerr;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
return std::wcout;
|
return std::wcout;
|
||||||
@@ -209,6 +209,8 @@ PICout::~PICout() {
|
|||||||
}
|
}
|
||||||
if (buffer_) {
|
if (buffer_) {
|
||||||
((NotifierObject *)Notifier::object())->finished(id_, buffer_);
|
((NotifierObject *)Notifier::object())->finished(id_, buffer_);
|
||||||
|
} else {
|
||||||
|
getStdStream(stream_).flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,13 +40,13 @@
|
|||||||
# define piCoutObj
|
# define piCoutObj
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define piCout PICout(piDebug, PICoutManipulators::StdOut)
|
# define piCout PICout(piDebug, PICoutStdStream::StdOut)
|
||||||
# define piCoutObj \
|
# define piCoutObj \
|
||||||
PICout(piDebug && debug(), PICoutManipulators::StdOut) \
|
PICout(piDebug && debug(), PICoutStdStream::StdOut) \
|
||||||
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||||
# define piCerr PICout(piDebug, PICoutManipulators::StdErr)
|
# define piCerr PICout(piDebug, PICoutStdStream::StdErr)
|
||||||
# define piCerrObj \
|
# define piCerrObj \
|
||||||
PICout(piDebug && debug(), PICoutManipulators::StdErr) \
|
PICout(piDebug && debug(), PICoutStdStream::StdErr) \
|
||||||
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
<< (PIStringAscii("[") + className() + (name().isEmpty() ? "]" : PIStringAscii(" \"") + name() + PIStringAscii("\"]")))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -131,19 +131,19 @@ enum PICoutFormat {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//! \~english Enum contains console streams
|
|
||||||
//! \~russian Перечисление с потоками консоли
|
|
||||||
enum PICoutStdStream {
|
|
||||||
StdOut /*! \~english Standard output stream \~russian Стандартный поток вывода */ = 0,
|
|
||||||
StdErr /*! \~english Standard error stream \~russian Стандартный поток ошибок */ = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef PIFlags<PICoutControl> PICoutControls;
|
typedef PIFlags<PICoutControl> PICoutControls;
|
||||||
|
|
||||||
} // namespace PICoutManipulators
|
} // namespace PICoutManipulators
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Enum contains console streams
|
||||||
|
//! \~russian Перечисление с потоками консоли
|
||||||
|
enum class PICoutStdStream {
|
||||||
|
StdOut /*! \~english Standard output stream \~russian Стандартный поток вывода */ = 0,
|
||||||
|
StdErr /*! \~english Standard error stream \~russian Стандартный поток ошибок */ = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//! \ingroup Core
|
//! \ingroup Core
|
||||||
//! \~\brief
|
//! \~\brief
|
||||||
//! \~english Universal output to console class.
|
//! \~english Universal output to console class.
|
||||||
@@ -152,11 +152,11 @@ class PIP_EXPORT PICout {
|
|||||||
public:
|
public:
|
||||||
//! \~english Default constructor with default features (AddSpaces and AddNewLine)
|
//! \~english Default constructor with default features (AddSpaces and AddNewLine)
|
||||||
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine)
|
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine)
|
||||||
PICout(int controls = PICoutManipulators::DefaultControls, PICoutManipulators::PICoutStdStream stream = PICoutManipulators::StdOut);
|
PICout(int controls = PICoutManipulators::DefaultControls, PICoutStdStream stream = PICoutStdStream::StdOut);
|
||||||
|
|
||||||
//! \~english Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
|
//! \~english Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
|
||||||
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
|
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
|
||||||
PICout(bool active, PICoutManipulators::PICoutStdStream stream = PICoutManipulators::StdOut);
|
PICout(bool active, PICoutStdStream stream = PICoutStdStream::StdOut);
|
||||||
|
|
||||||
PICout(const PICout & other);
|
PICout(const PICout & other);
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ public:
|
|||||||
|
|
||||||
//! \~english Output \a PIString to stdout
|
//! \~english Output \a PIString to stdout
|
||||||
//! \~russian Вывод \a PIString в stdout
|
//! \~russian Вывод \a PIString в stdout
|
||||||
static void stdoutPIString(const PIString & str, PICoutManipulators::PICoutStdStream s = PICoutManipulators::StdOut);
|
static void stdoutPIString(const PIString & str, PICoutStdStream s = PICoutStdStream::StdOut);
|
||||||
|
|
||||||
//! \~english Returns internal PIString buffer
|
//! \~english Returns internal PIString buffer
|
||||||
//! \~russian Возвращает внутренний PIString буфер
|
//! \~russian Возвращает внутренний PIString буфер
|
||||||
@@ -398,7 +398,7 @@ private:
|
|||||||
int int_base_ = 10, win_attr_ = 0, id_ = 0;
|
int int_base_ = 10, win_attr_ = 0, id_ = 0;
|
||||||
PIString * buffer_ = nullptr;
|
PIString * buffer_ = nullptr;
|
||||||
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
|
PICoutManipulators::PICoutControls ctrl_ = PICoutManipulators::DefaultControls;
|
||||||
PICoutManipulators::PICoutStdStream stream_ = PICoutManipulators::StdOut;
|
PICoutStdStream stream_ = PICoutStdStream::StdOut;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PICOUT_H
|
#endif // PICOUT_H
|
||||||
|
|||||||
@@ -529,6 +529,7 @@ void PIIODevice::configureFromVariant(const PIVariantTypes::IODevice & d) {
|
|||||||
|
|
||||||
|
|
||||||
void PIIODevice::splitFullPath(PIString fpwm, PIString * full_path, DeviceMode * mode, DeviceOptions * opts) {
|
void PIIODevice::splitFullPath(PIString fpwm, PIString * full_path, DeviceMode * mode, DeviceOptions * opts) {
|
||||||
|
fpwm.trim();
|
||||||
int dm = 0;
|
int dm = 0;
|
||||||
DeviceOptions op = 0;
|
DeviceOptions op = 0;
|
||||||
if (fpwm.find('(') > 0 && fpwm.find(')') > 0) {
|
if (fpwm.find('(') > 0 && fpwm.find(')') > 0) {
|
||||||
@@ -617,11 +618,12 @@ PIString PIIODevice::fullPathOptions() const {
|
|||||||
//! В метод \a configureFromFullPath() "full_path" передается без \a fullPathPrefix() и "://".
|
//! В метод \a configureFromFullPath() "full_path" передается без \a fullPathPrefix() и "://".
|
||||||
//! См. \ref PIIODevice_sec7
|
//! См. \ref PIIODevice_sec7
|
||||||
PIIODevice * PIIODevice::createFromFullPath(const PIString & full_path) {
|
PIIODevice * PIIODevice::createFromFullPath(const PIString & full_path) {
|
||||||
PIString prefix = full_path.left(full_path.find(":"));
|
PIString fp = full_path.trimmed();
|
||||||
|
PIString prefix = fp.left(fp.find(":"));
|
||||||
PIIODevice * nd = newDeviceByPrefix(prefix.dataAscii());
|
PIIODevice * nd = newDeviceByPrefix(prefix.dataAscii());
|
||||||
if (!nd) return nullptr;
|
if (!nd) return nullptr;
|
||||||
nd->configureFromFullPath(full_path.mid(prefix.length() + 3));
|
nd->configureFromFullPath(fp.mid(prefix.length() + 3));
|
||||||
cacheFullPath(full_path, nd);
|
cacheFullPath(fp, nd);
|
||||||
return nd;
|
return nd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
* This class helps to deserialize and invoke neccessarily methods.
|
* This class helps to deserialize and invoke neccessarily methods.
|
||||||
*
|
*
|
||||||
* Data packets with header and various data types can be automated by this class.
|
* Data packets with header and various data types can be automated by this class.
|
||||||
* Every key value mapped to event handler or lambda-function.
|
* Every key value mapped to object member function, lambda-function or functor.
|
||||||
*
|
*
|
||||||
* This class can remove \b switch-case with deserialization code and
|
* 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.
|
* replace it with several \a assign() calls, binded to ready-to-use event handlers.
|
||||||
@@ -48,30 +48,15 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* \section PIParseHelper_usage Usage
|
* \section PIParseHelper_usage Usage
|
||||||
* There are two variants: subclassing and aggregating.
|
|
||||||
*
|
*
|
||||||
* ### Subclass
|
* Create instance of %PIParseHelper, or subclass.
|
||||||
*
|
*
|
||||||
* Inherit your class from %PIParseHelper and construct it with \b this.
|
* In \a assign() methods you can use object member function, lambda-function
|
||||||
*
|
* or functor with 0 or 1 arguments,
|
||||||
* 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
|
* \section PIParseHelper_lambda Lambda-functions
|
||||||
* Assign methods that receive lambda-functions can`t accept direct lambda (\"[](){}\")
|
* \code assign(1, [this](const SomeStruct & s){}) \endcode
|
||||||
* 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
|
* \section PIParseHelper_examples Examples
|
||||||
@@ -87,56 +72,21 @@
|
|||||||
template<typename Key>
|
template<typename Key>
|
||||||
class PIParseHelper {
|
class PIParseHelper {
|
||||||
public:
|
public:
|
||||||
//! \brief Construct %PIParseHelper with target object \"p\"
|
//! \brief Construct %PIParseHelper
|
||||||
PIParseHelper(PIObject * p): parent(p) {}
|
PIParseHelper() {}
|
||||||
|
|
||||||
|
|
||||||
//! \brief Assign key \"key\" to event handler \"handler\" with 1 argument
|
//! \brief Assign key \"key\" to lambda-function \"func\" without arguments
|
||||||
template<typename T, typename Ret>
|
void assign(Key key, std::function<void()> func) {
|
||||||
void assign(Key key, Ret (*handler)(void *, T)) {
|
auto lf = [func](PIByteArray) { func(); };
|
||||||
if (!parent) return;
|
functions[key] << lf;
|
||||||
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
|
//! \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>
|
template<typename T>
|
||||||
void assign(Key key, std::function<void(T)> func) {
|
void assign(Key key, std::function<void(const T &)> func) {
|
||||||
if (!parent) return;
|
auto lf = [func](PIByteArray data) {
|
||||||
auto lf = [func](PIObject *, PIByteArray data) {
|
|
||||||
if (!data.isEmpty()) {
|
if (!data.isEmpty()) {
|
||||||
T v;
|
T v;
|
||||||
data >> v;
|
data >> v;
|
||||||
@@ -147,26 +97,44 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//! \brief Assign key \"key\" to lambda-function \"func\" without arguments
|
//! \brief Assign key \"key\" to member function of object \"obj\" without arguments
|
||||||
//! \note Important! Direct lambda functions are not allowed, see \ref PIParseHelper_lambda
|
template<typename O>
|
||||||
void assign(Key key, std::function<void()> func) {
|
void assign(Key key, O * obj, void (O::*member_func)()) {
|
||||||
if (!parent) return;
|
auto lf = [member_func, obj](PIByteArray) { (obj->*member_func)(); };
|
||||||
auto lf = [func](PIObject *, PIByteArray) { func(); };
|
|
||||||
functions[key] << lf;
|
functions[key] << lf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief Assign key \"key\" to member function of object \"obj\" with 1 argument
|
||||||
|
template<typename T, typename O>
|
||||||
|
void assign(Key key, O * obj, void (O::*member_func)(const T &)) {
|
||||||
|
auto lf = [member_func, obj](PIByteArray data) {
|
||||||
|
if (!data.isEmpty()) {
|
||||||
|
T v;
|
||||||
|
data >> v;
|
||||||
|
(obj->*member_func)(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
functions[key] << lf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \brief Assign key \"key\" to functor \"func\" with 0 or 1 argument
|
||||||
|
template<typename L>
|
||||||
|
void assign(Key key, L func) {
|
||||||
|
return assign(key, toStdFunction(func));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! \brief Deserialize data and invoke assigned to \"key\" methods
|
//! \brief Deserialize data and invoke assigned to \"key\" methods
|
||||||
void parse(Key key, PIByteArray ba) {
|
void parse(Key key, PIByteArray ba) {
|
||||||
if (!parent) return;
|
|
||||||
auto fl = functions.value(key);
|
auto fl = functions.value(key);
|
||||||
for (auto f: fl)
|
for (auto f: fl)
|
||||||
f(parent, ba);
|
f(ba);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PIMap<Key, PIVector<std::function<void(PIObject *, PIByteArray)>>> functions;
|
PIMap<Key, PIVector<std::function<void(PIByteArray)>>> functions;
|
||||||
PIObject * parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ public:
|
|||||||
//! Returns packet sinature, default 0xAFBE
|
//! Returns packet sinature, default 0xAFBE
|
||||||
ushort packetSign() const { return packet_sign; }
|
ushort packetSign() const { return packet_sign; }
|
||||||
|
|
||||||
|
//! Returns progress of current packet receive in bytes
|
||||||
|
int receivePacketProgress() const { return packet.size_s(); }
|
||||||
|
|
||||||
|
|
||||||
//! Set receive aggressive optimization. If yes then %PIStreamPacker doesn`t
|
//! Set receive aggressive optimization. If yes then %PIStreamPacker doesn`t
|
||||||
//! check every byte in incoming stream but check only begin of each read()
|
//! check every byte in incoming stream but check only begin of each read()
|
||||||
@@ -90,6 +93,8 @@ public:
|
|||||||
void assignDevice(PIIODevice * dev);
|
void assignDevice(PIIODevice * dev);
|
||||||
|
|
||||||
EVENT1(packetReceiveEvent, PIByteArray &, data);
|
EVENT1(packetReceiveEvent, PIByteArray &, data);
|
||||||
|
EVENT1(startPacketReceive, int, size);
|
||||||
|
EVENT0(endPacketReceive);
|
||||||
EVENT1(sendRequest, PIByteArray, data);
|
EVENT1(sendRequest, PIByteArray, data);
|
||||||
|
|
||||||
//! \handlers
|
//! \handlers
|
||||||
@@ -107,6 +112,12 @@ public:
|
|||||||
//! \fn void packetReceiveEvent(PIByteArray data)
|
//! \fn void packetReceiveEvent(PIByteArray data)
|
||||||
//! \brief Raise on packet successfully received
|
//! \brief Raise on packet successfully received
|
||||||
|
|
||||||
|
//! \fn void startPacketReceive(int size)
|
||||||
|
//! \brief Raise on start receive packet with overall size \"size\"
|
||||||
|
|
||||||
|
//! \fn void endPacketReceive()
|
||||||
|
//! \brief Raise on finish receive packet
|
||||||
|
|
||||||
//! \fn void sendRequest(PIByteArray data)
|
//! \fn void sendRequest(PIByteArray data)
|
||||||
//! \brief Raise from \a send() function. This data should
|
//! \brief Raise from \a send() function. This data should
|
||||||
//! be directly sended to your device. You can
|
//! be directly sended to your device. You can
|
||||||
|
|||||||
@@ -31,21 +31,6 @@
|
|||||||
|
|
||||||
namespace PIStateMachineHelpers {
|
namespace PIStateMachineHelpers {
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct FunctionType {
|
|
||||||
using Type = void;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename... Args>
|
|
||||||
struct FunctionType<Ret (Class::*)(Args...) const> {
|
|
||||||
using Type = std::function<Ret(Args...)>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename L>
|
|
||||||
typename FunctionType<decltype(&L::operator())>::Type toStdFunction(L const & func) {
|
|
||||||
return func;
|
|
||||||
}
|
|
||||||
|
|
||||||
class FunctionBase {
|
class FunctionBase {
|
||||||
public:
|
public:
|
||||||
virtual ~FunctionBase() {}
|
virtual ~FunctionBase() {}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public:
|
|||||||
|
|
||||||
template<typename L>
|
template<typename L>
|
||||||
PITransitionBase * addGuard(L f) {
|
PITransitionBase * addGuard(L f) {
|
||||||
return addGuard(PIStateMachineHelpers::toStdFunction(f));
|
return addGuard(toStdFunction(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
|
|||||||
@@ -1197,6 +1197,17 @@ int PIString::entries(const PIChar c) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int PIString::entries(const PIString & str) const {
|
||||||
|
int sz = size_s(), ssz = str.size_s();
|
||||||
|
if (ssz == 0 || sz < ssz) return 0;
|
||||||
|
int btc = str.size_s() * sizeof(PIChar), ret = 0;
|
||||||
|
for (int i = 0; i < sz - ssz + 1; ++i) {
|
||||||
|
if (piCompareBinary(d.data(i), str.d.data(0), btc)) ++ret;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PIString::startsWith(const PIChar c) const {
|
bool PIString::startsWith(const PIChar c) const {
|
||||||
if (isEmpty()) return false;
|
if (isEmpty()) return false;
|
||||||
return front() == c;
|
return front() == c;
|
||||||
|
|||||||
@@ -1271,6 +1271,16 @@ public:
|
|||||||
//! piCout << PIString(".str.0").entries("0"); // 1
|
//! piCout << PIString(".str.0").entries("0"); // 1
|
||||||
//! \endcode
|
//! \endcode
|
||||||
int entries(const PIChar c) const;
|
int entries(const PIChar c) const;
|
||||||
|
int entries(char c) const { return entries(PIChar(c)); }
|
||||||
|
|
||||||
|
//! \~english Returns number of occurrences of string "str".
|
||||||
|
//! \~russian Возвращает число вхождений строк "str".
|
||||||
|
//! \~\details
|
||||||
|
//! \~\code
|
||||||
|
//! piCout << PIString("hello locale").entries("lo"); // 2
|
||||||
|
//! piCout << PIString("hello locale").entries("lo lo"); // 1
|
||||||
|
//! \endcode
|
||||||
|
int entries(const PIString & str) const;
|
||||||
|
|
||||||
//! \~english Returns if string starts with "c".
|
//! \~english Returns if string starts with "c".
|
||||||
//! \~russian Возвращает начинается ли строка с "c".
|
//! \~russian Возвращает начинается ли строка с "c".
|
||||||
|
|||||||
16
main.cpp
16
main.cpp
@@ -68,6 +68,22 @@ protected:
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
|
/*piCout << PIString("hello locale").entries("lo"); // 2
|
||||||
|
piCout << PIString("hello locale").entries("lo lo"); // 1
|
||||||
|
piCout << ("3hello4"_u8);
|
||||||
|
piCout << ("3hello4"_u8).entries("hello1");
|
||||||
|
piCout << ("3hello4"_u8).entries("hello");
|
||||||
|
piCout << ("3hello4"_u8).entries("l");
|
||||||
|
piCout << ("3hello4"_u8).entries("ello");
|
||||||
|
piCout << ("3hello4"_u8).entries("hell");
|
||||||
|
piCout << ("2hellohello1"_u8);
|
||||||
|
piCout << ("2hellohello1"_u8).entries("hello1");
|
||||||
|
piCout << ("2hellohello1"_u8).entries("hello");
|
||||||
|
piCout << ("2hellohello1"_u8).entries("l");
|
||||||
|
piCout << ("2hellohello1"_u8).entries("ello");
|
||||||
|
piCout << ("2hellohello1"_u8).entries("hell");
|
||||||
|
return 0;*/
|
||||||
|
|
||||||
PILog log;
|
PILog log;
|
||||||
log.setColorConsole(false);
|
log.setColorConsole(false);
|
||||||
log.setOutput(PILog::File, false);
|
log.setOutput(PILog::File, false);
|
||||||
|
|||||||
Reference in New Issue
Block a user