74 Commits

Author SHA1 Message Date
ae29b4514c translation for russian starts 2022-03-14 12:11:46 +03:00
2a877fbb6b pip_cmg supports for "simple-stream" PIMETA tag for structs and classes for simple de/serialization without PIChunkStream 2022-03-11 14:39:08 +03:00
2a6ebc9d8d piCompare change position 2022-02-14 19:12:41 +03:00
1918e55a97 piCompare use piAbs 2022-02-08 00:33:12 +03:00
eb6d378de2 deploy tool unchained from "grep" and support qt6 2022-01-31 19:55:23 +03:00
b1b174ba64 missed include 2022-01-23 12:59:13 +03:00
1d9a39f792 piCompare 2022-01-10 17:10:41 +03:00
cbdaabee4a some build fixes 2022-01-07 01:58:38 +03:00
3c8ccf357b PIFile::openTemporary on Windows
PIPair from std::tuple
2021-12-24 14:41:18 +03:00
Andrey
92b20f6f46 PIByteArray getRange 2021-11-16 15:22:03 +03:00
04d7ed77d9 Merge pull request 'condvar_use' (#82) from condvar_use into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/82
2021-11-16 14:49:52 +03:00
a2a205cfd2 version 2.33.0
piMinSleep() method
2021-11-16 14:43:57 +03:00
d3b6597042 PIMap range-for decomposition declaration support 2021-11-01 23:29:42 +03:00
Andrey
48c885e12a PIThreadNotifier, rewrite PIObject::deleteLater()
tests for PIThreadNotifier and PIObject::deleteLater()
2021-10-29 18:20:48 +03:00
Andrey
6e5a5a6ade remove msleep, clean PIConditionVariable, rewrite pipipelinethread, etc... 2021-10-29 16:52:03 +03:00
21e03fc8cb flags 2021-10-27 10:53:27 +03:00
b85de0d704 work with PIFile::openTemporary() on Windows 2021-10-26 13:50:27 +03:00
peri4
f781cc3846 binary log improvements 2021-10-21 18:48:01 +03:00
peri4
1cb3d4ffe9 PIBinaryLog fix 2021-10-14 12:45:01 +03:00
peri4
9293706634 PISerial 14400 baudrate only for Windows 2021-10-08 22:11:47 +03:00
peri4
fde6bdf17f PISerial 14400 baudrate 2021-10-08 22:02:51 +03:00
Andrey
a1c1fd8339 Merge branch 'master' of https://git.shs.tools/SHS/pip 2021-10-08 15:16:19 +03:00
Andrey
01b39dc75f pip_cmg fix macros name 2021-10-08 15:16:08 +03:00
07ec32c969 tests 2021-10-05 20:31:00 +03:00
042366e19e Merge branch 'PIMathMatrixTests1-10' 2021-10-04 22:14:38 +03:00
948a90fcd9 option revert 2021-10-04 22:14:15 +03:00
c404688bbd more safety for PIObject::Connection::disconnect() 2021-10-04 21:57:34 +03:00
aa76a15f40 version 2.32.0
PIObject::Connection struct
2021-10-04 21:50:49 +03:00
Andrey
ca20785b53 revert piDisconnectAll 2021-10-04 15:07:14 +03:00
Andrey
13d0b2f960 remove piDisconnectAll 2021-10-04 15:05:58 +03:00
Andrey
46571ac39f piDisconnectAll private 2021-10-04 14:18:23 +03:00
36d770ea2e Merge pull request 'piobject_tests' (#80) from piobject_tests into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/80
2021-10-04 12:11:51 +03:00
Andrey
bc7d129a9e piobject/connect.cpp tests 2021-10-04 12:07:01 +03:00
8accc28804 test fix 2021-09-30 19:28:30 +03:00
Andrey
62e130f91b disconnect test failed 2021-09-30 18:41:01 +03:00
a009221092 pidisconnect now work with lambdas 2021-09-30 16:21:28 +03:00
dedc35b466 new class PIThreadPoolLoop 2021-09-24 16:03:20 +03:00
5e33587703 PISerial::setBreak linux fix 2021-09-17 21:27:24 +03:00
950f6830da old gcc pithread fix 2021-09-17 21:20:21 +03:00
Andrey
19a8ca84e6 PIByteArray checksumPlain invert flag
fix PISerial setBreak
2021-09-16 16:18:20 +03:00
Andrey
ece3fb1536 PISerial setBreak 2021-09-16 12:18:17 +03:00
0d119502a8 PIDeque functions same as PIVector
code brush
fix indexOf and entries with start<0
2021-09-09 18:01:57 +03:00
cc5951cfc3 PIVector getRange removeWhere 2021-09-09 17:38:28 +03:00
61d42e0ac5 PIVector: map, reduce
rename arguments in uniform style
2021-09-07 18:29:09 +03:00
127935086c PIVector: any, every, indexWhere, lastIndexWhere
start arg in indexOf, entries, lastIndexOf
and some code brush
2021-09-07 17:29:24 +03:00
76ed60edf3 code brush 2021-09-07 15:39:44 +03:00
3b0a1c70fe documentation fix 2021-09-03 17:12:46 +03:00
186e07e45d PICodeInfo::EnumInfo toPIVariantEnum 2021-09-03 16:19:57 +03:00
047cff7d6e version 2021-09-03 12:42:29 +03:00
305275e3ac PICodeParser namespaces fix 2021-09-03 11:39:26 +03:00
efb0d5f4f9 PICodeParser predefined PIP macros 2021-09-03 11:20:38 +03:00
991a074538 version 2.30
PIStreamPacker remove progresses
picloud various fixes
2021-09-01 23:48:13 +03:00
f82b6c12ee cloud_dispatcher patch 2021-09-01 22:43:40 +03:00
00edfa4ef0 cloud data send optimize 2021-09-01 17:48:58 +03:00
35a3ce6402 picloudtcp.cpp revert some mutex 2021-09-01 10:56:11 +03:00
be3ce454a0 picloud multithread fix 2021-08-31 19:40:22 +03:00
4c85206cfa version 2021-08-23 14:07:45 +03:00
5ecdcbe46e Merge pull request 'cloud_debug' (#78) from cloud_debug into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/78
2021-08-23 13:58:08 +03:00
c937d7251a it works 2021-08-23 13:56:21 +03:00
1cc46468c1 fail 2021-08-20 18:30:19 +03:00
5cc8ef1eb0 fail reconnect 2021-08-20 18:25:59 +03:00
99e135caa2 PICloudClient disconnect 2021-08-20 17:22:25 +03:00
9de7045d63 picloud revert to condvars and fix 2021-08-20 16:36:28 +03:00
0e65151e9f PIEthernet error 232
PICloud many fixes
PIBroadcast recursive fix
2021-08-20 10:55:47 +03:00
3c20728210 version 2021-08-19 18:29:05 +03:00
4c0530d89a picloud ping and fix big bugs 2021-08-19 18:13:05 +03:00
f5af8a1da9 disable autostart pibroadcast 2021-08-19 15:02:30 +03:00
44b9c37391 PICloudClient now soft stop thread when closed
last cmake changes
2021-08-16 22:30:56 +03:00
97b0b6fc0c picloud hash key 2021-08-12 22:05:02 +03:00
1a2e9afaef PIVector compare operators 2021-08-12 21:52:14 +03:00
39a3a23a24 PIByteArray compare operators 2021-08-12 21:41:22 +03:00
ee131921a0 add PIByteArray operator <, fix picloud 2021-08-12 20:22:43 +03:00
f8818c8537 picloud patch 2021-08-12 19:50:17 +03:00
b07242226e Tests1-10 2021-02-25 15:41:20 +03:00
80 changed files with 2686 additions and 1493 deletions

View File

@@ -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 2) set(pip_MAJOR 2)
set(pip_MINOR 28) set(pip_MINOR 33)
set(pip_REVISION 1) set(pip_REVISION 1)
set(pip_SUFFIX ) set(pip_SUFFIX )
set(pip_COMPANY SHS) set(pip_COMPANY SHS)
@@ -284,7 +284,7 @@ endif()
if(APPLE) if(APPLE)
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE) add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
endif() endif()
if ((NOT DEFINED LIBPROJECT) AND (DEFINED ANDROID_PLATFORM)) if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
include_directories(${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include) include_directories(${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include)
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include") #message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include") #message("${ANDROID_NDK}/sysroot/usr/include")
@@ -320,7 +320,7 @@ if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /Ob2 /Ot /W0") set(CMAKE_CXX_FLAGS "/O2 /Ob2 /Ot /W0")
endif() endif()
else() else()
set(${CMAKE_CXX_FLAGS} "${CMAKE_CXX_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
if(DEFINED ENV{QNX_HOST} OR PIP_FREERTOS) if(DEFINED ENV{QNX_HOST} OR PIP_FREERTOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32")
endif() endif()
@@ -567,8 +567,8 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
list(APPEND DOXY_INPUT "\"${F}\"") list(APPEND DOXY_INPUT "\"${F}\"")
endforeach(F) endforeach(F)
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\"") string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\"")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${DOXY_INPUT}") string(REPLACE ";" " " DOXY_INCLUDE_PATH "${PIP_INCLUDES}")
string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS};DOXYGEN;PIOBJECT;PIOBJECT_SUBCLASS") string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS}")
add_documentation(doc doc/Doxyfile.in) add_documentation(doc doc/Doxyfile.in)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL)
endif() endif()

View File

@@ -71,6 +71,10 @@ if (NOT BUILDING_pip)
find_library(PTHREAD_LIBRARY pthread) find_library(PTHREAD_LIBRARY pthread)
find_library(UTIL_LIBRARY util) find_library(UTIL_LIBRARY util)
set(_PIP_ADD_LIBS_ ${PTHREAD_LIBRARY} ${UTIL_LIBRARY}) set(_PIP_ADD_LIBS_ ${PTHREAD_LIBRARY} ${UTIL_LIBRARY})
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT PIP_FREERTOS))
find_library(RT_LIBRARY rt)
list(APPEND _PIP_ADD_LIBS_ ${RT_LIBRARY})
endif()
list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_}) list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_})
endif() endif()
endif() endif()

View File

@@ -2164,7 +2164,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator. # recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = ${DOXY_DEFINES} PREDEFINED = DOXYGEN PIOBJECT PIOBJECT_SUBCLASS PIIODEVICE NO_COPY_CLASS ${DOXY_DEFINES}
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this

View File

@@ -2,7 +2,7 @@
PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) { PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) {
eth.setDebug(false);
} }

View File

@@ -25,29 +25,36 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode)
tcp.setRole(PICloud::TCP::Client); tcp.setRole(PICloud::TCP::Client);
setName("cloud_client"); setName("cloud_client");
is_connected = false; is_connected = false;
CONNECTL(&eth, connected, [this](){tcp.sendStart();}); is_deleted = false;
// setReopenEnabled(false);
CONNECTL(&eth, connected, [this](){opened_ = true; tcp.sendStart();});
CONNECTU(&streampacker, packetReceiveEvent, this, _readed); CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, disconnected, [this](bool){ CONNECTL(&eth, disconnected, [this](bool){
piCoutObj << "disconnected"; if (is_deleted) return;
bool need_disconn = is_connected;
//piCoutObj << "eth disconnected";
static_cast<PIThread*>(&eth)->stop();
opened_ = false; opened_ = false;
is_connected = false; internalDisconnect();
cond_connect.notifyOne(); if (need_disconn)
cond_buff.notifyOne(); disconnected();
piMSleep(100); //piCoutObj << "eth disconnected done";
}); });
} }
PICloudClient::~PICloudClient() { PICloudClient::~PICloudClient() {
eth.close(); //piCoutObj << "~PICloudClient()";
if (is_connected) { PIThread::stop();
is_connected = false; //eth.close();
disconnected(); //if (is_connected) disconnected();
cond_buff.notifyOne();
cond_connect.notifyOne();
}
close(); close();
stop(); //piCoutObj << "~PICloudClient() closed";
internalDisconnect();
// stop(false);
is_deleted = true;
internalDisconnect();
//piCoutObj << "~PICloudClient() done";
} }
@@ -63,80 +70,100 @@ void PICloudClient::setKeepConnection(bool on) {
bool PICloudClient::openDevice() { bool PICloudClient::openDevice() {
// piCout << "PICloudClient open device" << path(); //piCoutObj << "open";// << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false); bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
if (op) { if (op) {
mutex_buff.lock(); mutex_connect.lock();
eth.startThreadedRead(); eth.startThreadedRead();
bool conn_ok = cond_connect.waitFor(mutex_buff, (int)eth.readTimeout(), [this](){return isConnected();}); //piCoutObj << "connecting...";
piCoutObj << "conn_ok" << conn_ok; bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout());
mutex_buff.unlock(); //piCoutObj << "conn_ok" << conn_ok << is_connected;
mutex_connect.unlock();
if (!conn_ok) { if (!conn_ok) {
mutex_connect.lock();
eth.stop(); eth.stop();
eth.close(); eth.close();
piMSleep(100); mutex_connect.unlock();
} }
return isConnected(); return is_connected;
} else { } else {
eth.close(); //eth.close();
return false; return false;
} }
} }
bool PICloudClient::closeDevice() { bool PICloudClient::closeDevice() {
//PIThread::stop();
if (is_connected) { if (is_connected) {
is_connected = false; internalDisconnect();
disconnected();
cond_buff.notifyOne();
cond_connect.notifyOne();
} }
eth.stop(); eth.stop();
if (eth.isOpened()) eth.close(); eth.close();
return true; return true;
} }
int PICloudClient::readDevice(void * read_to, int max_size) { int PICloudClient::readDevice(void * read_to, int max_size) {
// piCoutObj << "readDevice"; if (is_deleted) return -1;
if (!is_connected) return -1; //piCoutObj << "readDevice";
if (!is_connected && eth.isClosed()) openDevice();
int sz = -1;
mutex_buff.lock(); mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();}); cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
int sz = piMini(max_size, buff.size()); if (is_connected) {
sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz); memcpy(read_to, buff.data(), sz);
buff.remove(0, sz); buff.remove(0, sz);
}
mutex_buff.unlock(); mutex_buff.unlock();
if (!is_connected) opened_ = false;
//piCoutObj << "readDevice done" << sz;
return sz; return sz;
} }
int PICloudClient::writeDevice(const void * data, int size) { int PICloudClient::writeDevice(const void * data, int size) {
if (is_deleted) return -1;
// piCoutObj << "writeDevice"; // piCoutObj << "writeDevice";
return tcp.sendData(PIByteArray(data, size)); return tcp.sendData(PIByteArray(data, size));
} }
void PICloudClient::internalDisconnect() {
is_connected = false;
cond_buff.notifyOne();
cond_connect.notifyOne();
streampacker.clear();
buff.clear();
}
void PICloudClient::_readed(PIByteArray & ba) { void PICloudClient::_readed(PIByteArray & ba) {
mutex_buff.lock(); if (is_deleted) return;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba); PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
//piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second;
if (hdr.second == tcp.role()) { if (hdr.second == tcp.role()) {
switch (hdr.first) { switch (hdr.first) {
case PICloud::TCP::Connect: case PICloud::TCP::Connect:
if (tcp.parseConnect(ba) == 1) { if (tcp.parseConnect(ba) == 1) {
mutex_connect.lock();
is_connected = true; is_connected = true;
connected(); mutex_connect.unlock();
cond_connect.notifyOne(); cond_connect.notifyOne();
connected();
} }
break; break;
case PICloud::TCP::Disconnect: case PICloud::TCP::Disconnect:
is_connected = false; static_cast<PIThread*>(&eth)->stop();
eth.stop(); opened_ = false;
eth.close(); eth.close();
disconnected();
break; break;
case PICloud::TCP::Data: case PICloud::TCP::Data:
if (is_connected) { if (is_connected) {
mutex_buff.lock();
buff.append(ba); buff.append(ba);
mutex_buff.unlock();
cond_buff.notifyOne(); cond_buff.notifyOne();
} }
break; break;
@@ -145,7 +172,7 @@ void PICloudClient::_readed(PIByteArray & ba) {
} }
//piCoutObj << "readed" << ba.toHex(); //piCoutObj << "readed" << ba.toHex();
} }
mutex_buff.unlock(); while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); //piCoutObj << "_readed done";
} }

View File

@@ -26,12 +26,17 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode)
tcp.setServerName(server_name); tcp.setServerName(server_name);
setName("cloud_server__" + server_name); setName("cloud_server__" + server_name);
CONNECTU(&streampacker, packetReceiveEvent, this, _readed); CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, connected, [this](){tcp.sendStart();}); CONNECTL(&eth, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();});
CONNECTL(&eth, disconnected, [this](bool){ CONNECTL(&eth, disconnected, [this](bool){
piCoutObj << "disconnected"; piCoutObj << "disconnected";
static_cast<PIThread*>(&eth)->stop();
opened_ = false; opened_ = false;
ping_timer.stop(false);
piMSleep(100); piMSleep(100);
}); });
CONNECTL(&ping_timer, tickEvent, [this] (void *, int){
if (eth.isConnected()) tcp.sendPing();
});
} }
@@ -54,12 +59,14 @@ PIVector<PICloudServer::Client *> PICloudServer::clients() const {
bool PICloudServer::openDevice() { bool PICloudServer::openDevice() {
piCout << "PICloudServer open device" << path(); //piCout << "PICloudServer open device" << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false); bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
if (op) { if (op) {
eth.startThreadedRead(); eth.startThreadedRead();
ping_timer.start(5000);
return true; return true;
} }
ping_timer.stop(false);
eth.close(); eth.close();
return false; return false;
} }
@@ -67,6 +74,7 @@ bool PICloudServer::openDevice() {
bool PICloudServer::closeDevice() { bool PICloudServer::closeDevice() {
eth.stop(); eth.stop();
ping_timer.stop(false);
clients_mutex.lock(); clients_mutex.lock();
for (auto c : clients_) { for (auto c : clients_) {
c->close(); c->close();
@@ -82,7 +90,8 @@ bool PICloudServer::closeDevice() {
int PICloudServer::readDevice(void * read_to, int max_size) { int PICloudServer::readDevice(void * read_to, int max_size) {
//piCoutObj << "readDevice"; //piCoutObj << "readDevice";
piMSleep(eth.readTimeout()); if (!opened_) openDevice();
else piMSleep(eth.readTimeout());
return -1; return -1;
} }
@@ -126,22 +135,26 @@ bool PICloudServer::Client::openDevice() {
bool PICloudServer::Client::closeDevice() { bool PICloudServer::Client::closeDevice() {
PIThread::stop(false);
if (is_connected) { if (is_connected) {
server->clientDisconnect(client_id); server->clientDisconnect(client_id);
is_connected = false; is_connected = false;
cond_buff.notifyOne();
} }
cond_buff.notifyOne();
return true; return true;
} }
int PICloudServer::Client::readDevice(void * read_to, int max_size) { int PICloudServer::Client::readDevice(void * read_to, int max_size) {
if (!is_connected) return -1; if (!is_connected) return -1;
int sz = -1;
mutex_buff.lock(); mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();}); cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
int sz = piMini(max_size, buff.size()); if (is_connected) {
sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz); memcpy(read_to, buff.data(), sz);
buff.remove(0, sz); buff.remove(0, sz);
}
mutex_buff.unlock(); mutex_buff.unlock();
return sz; return sz;
} }
@@ -158,7 +171,7 @@ void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
buff.append(ba); buff.append(ba);
cond_buff.notifyOne(); cond_buff.notifyOne();
mutex_buff.unlock(); mutex_buff.unlock();
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
} }
@@ -174,7 +187,7 @@ void PICloudServer::_readed(PIByteArray & ba) {
if (oc) { if (oc) {
tcp.sendDisconnected(id); tcp.sendDisconnected(id);
} else { } else {
piCoutObj << "new Client" << id; //piCoutObj << "new Client" << id;
Client * c = new Client(this, id); Client * c = new Client(this, id);
CONNECTU(c, deleted, this, clientDeleted); CONNECTU(c, deleted, this, clientDeleted);
clients_mutex.lock(); clients_mutex.lock();
@@ -186,7 +199,7 @@ void PICloudServer::_readed(PIByteArray & ba) {
} break; } break;
case PICloud::TCP::Disconnect: { case PICloud::TCP::Disconnect: {
uint id = tcp.parseDisconnect(ba); uint id = tcp.parseDisconnect(ba);
piCoutObj << "remove Client" << id; //piCoutObj << "remove Client" << id;
clients_mutex.lock(); clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr); Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock(); clients_mutex.unlock();

View File

@@ -24,7 +24,7 @@
#include "pistreampacker.h" #include "pistreampacker.h"
const char hash_def_key[] = "_picrypt_"; const char hash_cloud_key[] = "_picloud_";
PICloud::TCP::Header::Header() { PICloud::TCP::Header::Header() {
@@ -33,7 +33,7 @@ PICloud::TCP::Header::Header() {
PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) { PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) {
streampacker->setMaxPacketSize(63*1024);
} }
void PICloud::TCP::setRole(PICloud::TCP::Role r) { void PICloud::TCP::setRole(PICloud::TCP::Role r) {
@@ -43,7 +43,7 @@ void PICloud::TCP::setRole(PICloud::TCP::Role r) {
void PICloud::TCP::setServerName(const PIString & server_name_) { void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_; server_name = server_name_;
suuid = PICrypt::hash(server_name_); suuid = PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
} }
@@ -62,7 +62,9 @@ void PICloud::TCP::sendStart() {
PIByteArray ba; PIByteArray ba;
ba << header; ba << header;
ba.append(suuid); ba.append(suuid);
//mutex_send.lock();
streampacker->send(ba); streampacker->send(ba);
//mutex_send.unlock();
} }
@@ -70,7 +72,9 @@ void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect; header.type = PICloud::TCP::Connect;
PIByteArray ba; PIByteArray ba;
ba << header << client_id; ba << header << client_id;
// mutex_send.lock();
streampacker->send(ba); streampacker->send(ba);
// mutex_send.unlock();
} }
@@ -78,7 +82,9 @@ void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect; header.type = PICloud::TCP::Disconnect;
PIByteArray ba; PIByteArray ba;
ba << header << client_id; ba << header << client_id;
// mutex_send.lock();
streampacker->send(ba); streampacker->send(ba);
// mutex_send.unlock();
} }
@@ -87,8 +93,10 @@ int PICloud::TCP::sendData(const PIByteArray & data) {
PIByteArray ba; PIByteArray ba;
ba << header; ba << header;
ba.append(data); ba.append(data);
// piCout << "sendData" << ba.toHex(); // piCout << "[PICloud::TCP] sendData" << ba.toHex();
mutex_send.lock();
streampacker->send(ba); streampacker->send(ba);
mutex_send.unlock();
return data.size_s(); return data.size_s();
} }
@@ -98,11 +106,24 @@ int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) {
PIByteArray ba; PIByteArray ba;
ba << header << client_id; ba << header << client_id;
ba.append(data); ba.append(data);
mutex_send.lock();
streampacker->send(ba); streampacker->send(ba);
mutex_send.unlock();
return data.size_s(); return data.size_s();
} }
void PICloud::TCP::sendPing() {
header.type = PICloud::TCP::Ping;
PIByteArray ba;
ba << header;
ba.append(suuid);
mutex_send.lock();
streampacker->send(ba);
mutex_send.unlock();
}
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) { PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret; PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret;
ret.first = InvalidType; ret.first = InvalidType;
@@ -120,11 +141,8 @@ PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteA
} }
PIByteArray PICloud::TCP::parseData(PIByteArray & ba) { bool PICloud::TCP::canParseData(PIByteArray & ba) {
if (header.role == Client) { return header.role == Client;
return ba;
}
return PIByteArray();
} }
@@ -133,7 +151,7 @@ PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) {
ret.first = 0; ret.first = 0;
if (header.role == Server) { if (header.role == Server) {
ba >> ret.first; ba >> ret.first;
ret.second = ba; ret.second.swap(ba);
} }
return ret; return ret;
} }

View File

@@ -23,6 +23,7 @@
# include <fcntl.h> # include <fcntl.h>
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE # ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
@@ -108,16 +109,13 @@ void PIScreen::SystemConsole::end() {
void PIScreen::SystemConsole::prepare() { void PIScreen::SystemConsole::prepare() {
int w, h; int w = 80, h = 24;
#ifdef WINDOWS #ifdef WINDOWS
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1; w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1;
h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1; h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1;
#else #else
# ifdef FREERTOS # ifndef FREERTOS
w = 80;
h = 24;
# else
winsize ws; winsize ws;
ioctl(0, TIOCGWINSZ, &ws); ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col; w = ws.ws_col;

View File

@@ -22,6 +22,7 @@
#ifndef FREERTOS #ifndef FREERTOS
#ifdef WINDOWS #ifdef WINDOWS
# include <windows.h> # include <windows.h>
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# include <winuser.h> # include <winuser.h>
#else #else

View File

@@ -169,6 +169,19 @@ PIByteArray PICrypt::hash(const PIByteArray & data) {
} }
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char *key, size_t keylen) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
size_t PICrypt::sizeHash() { size_t PICrypt::sizeHash() {
#ifdef PIP_CRYPT #ifdef PIP_CRYPT
return crypto_generichash_BYTES; return crypto_generichash_BYTES;

View File

@@ -53,8 +53,6 @@ PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
_started = false; _started = false;
_send_only = send_only; _send_only = send_only;
_reinit = true; _reinit = true;
//initMcast(PIEthernet::allAddresses());
PIThread::start(3000);
} }
@@ -140,7 +138,6 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
piForeachC (PIEthernet::Address & a, al) { piForeachC (PIEthernet::Address & a, al) {
PIEthernet * ce = 0; PIEthernet * ce = 0;
//piCout << "mcast try" << a; //piCout << "mcast try" << a;
if (_channels[Multicast]) { if (_channels[Multicast]) {
ce = new PIEthernet(); ce = new PIEthernet();
ce->setDebug(false); ce->setDebug(false);
@@ -184,7 +181,6 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
eth_mcast << ce; eth_mcast << ce;
} }
} }
} }
if (_channels[Loopback]) { if (_channels[Loopback]) {
@@ -207,11 +203,14 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
void PIBroadcast::send(const PIByteArray & data) { void PIBroadcast::send(const PIByteArray & data) {
if (!isRunning()) {
reinit();
PIThread::start(3000);
}
PIByteArray cd = cryptData(data); PIByteArray cd = cryptData(data);
if (cd.isEmpty()) return; if (cd.isEmpty()) return;
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast) piForeach (PIEthernet * e, eth_mcast) e->send(cd);
e->send(cd);
if (eth_lo) { if (eth_lo) {
for (int i = 0; i < lo_pcnt; ++i) { for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->send("127.0.0.1", lo_port + i, cd); eth_lo->send("127.0.0.1", lo_port + i, cd);
@@ -221,30 +220,31 @@ void PIBroadcast::send(const PIByteArray & data) {
void PIBroadcast::startRead() { void PIBroadcast::startRead() {
if (!isRunning()) {
_started = false;
reinit();
PIThread::start(3000);
}
if (_send_only) return; if (_send_only) return;
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast) piForeach (PIEthernet * e, eth_mcast) e->startThreadedRead();
e->startThreadedRead(); if (eth_lo) eth_lo->startThreadedRead();
if (eth_lo)
eth_lo->startThreadedRead();
_started = true; _started = true;
} }
void PIBroadcast::stopRead() { void PIBroadcast::stopRead() {
if (isRunning()) stop();
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast) piForeach (PIEthernet * e, eth_mcast) e->stopThreadedRead();
e->stopThreadedRead(); if (eth_lo) eth_lo->stopThreadedRead();
if (eth_lo)
eth_lo->stopThreadedRead();
_started = false; _started = false;
} }
void PIBroadcast::reinit() { void PIBroadcast::reinit() {
initAll(PIEthernet::allAddresses()); initAll(PIEthernet::allAddresses());
if (_started) if (_started) startRead();
startRead();
} }
@@ -261,8 +261,6 @@ void PIBroadcast::run() {
mcast_mutex.lock(); mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al); bool r = _reinit, ac = (al != prev_al);
mcast_mutex.unlock(); mcast_mutex.unlock();
if (ac || r) if (ac || r) reinit();
reinit(); if (ac) addressesChanged();
if (ac)
addressesChanged();
} }

View File

@@ -68,6 +68,13 @@ void PIStreamPacker::setCryptSizeEnabled(bool on) {
} }
void PIStreamPacker::clear() {
packet.clear();
packet_size = -1;
stream.clear();
}
void PIStreamPacker::send(const PIByteArray & data) { void PIStreamPacker::send(const PIByteArray & data) {
if (data.isEmpty()) return; if (data.isEmpty()) return;
PIByteArray cd; PIByteArray cd;
@@ -94,31 +101,12 @@ void PIStreamPacker::send(const PIByteArray & data) {
hdr << int(cd.size_s()); hdr << int(cd.size_s());
cd.insert(0, hdr); cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0; int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = true;
prog_s.bytes_all = data.size_s();
prog_s.bytes_current = 0;
prog_s.progress = 0.;
prog_s_mutex.unlock();
}
for (int i = 0; i < pcnt; ++i) { for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst); if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else part = PIByteArray(cd.data(pst), max_packet_size); else part = PIByteArray(cd.data(pst), max_packet_size);
//piCout << "send" << part.size(); //piCout << "send" << part.size();
sendRequest(part); sendRequest(part);
pst += max_packet_size; pst += max_packet_size;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.bytes_current += part.size_s();
prog_s.progress = (double)prog_s.bytes_current / prog_s.bytes_all;
prog_s_mutex.unlock();
}
}
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = false;
prog_s_mutex.unlock();
} }
} }
@@ -166,22 +154,10 @@ void PIStreamPacker::received(const PIByteArray & data) {
packet_size = sz; packet_size = sz;
if (packet_size == 0) if (packet_size == 0)
packet_size = -1; packet_size = -1;
else {
prog_r_mutex.lock();
prog_r.active = true;
prog_r.bytes_all = packet_size;
prog_r.bytes_current = 0;
prog_r.progress = 0.;
prog_r_mutex.unlock();
}
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());
packet.append(stream.data(), ps); packet.append(stream.data(), ps);
prog_r_mutex.lock();
prog_r.bytes_current = packet.size_s();
prog_r.progress = (double)prog_r.bytes_current / piMaxi(1, prog_r.bytes_all);
prog_r_mutex.unlock();
stream.remove(0, ps); stream.remove(0, ps);
if (packet.size_s() == packet_size) { if (packet.size_s() == packet_size) {
PIByteArray cd; PIByteArray cd;
@@ -211,9 +187,6 @@ void PIStreamPacker::received(const PIByteArray & data) {
} }
packet.clear(); packet.clear();
packet_size = -1; packet_size = -1;
prog_r_mutex.lock();
prog_r.active = false;
prog_r_mutex.unlock();
} }
} }
} }
@@ -227,30 +200,3 @@ void PIStreamPacker::assignDevice(PIIODevice * dev) {
CONNECTU(dev, threadedReadEvent, this, received); CONNECTU(dev, threadedReadEvent, this, received);
CONNECTU(this, sendRequest, dev, write); CONNECTU(this, sendRequest, dev, write);
} }
PIStreamPacker::Progress PIStreamPacker::progressSend() const {
PIStreamPacker::Progress ret;
prog_s_mutex.lock();
ret = prog_s;
prog_s_mutex.unlock();
return ret;
}
PIStreamPacker::Progress PIStreamPacker::progressReceive() const {
PIStreamPacker::Progress ret;
prog_r_mutex.lock();
ret = prog_r;
prog_r_mutex.unlock();
return ret;
}
PIStreamPacker::Progress::Progress() {
active = false;
bytes_all = bytes_current = 0;
progress = 0.;
}

View File

@@ -52,12 +52,15 @@ protected:
private: private:
EVENT_HANDLER1(void, _readed, PIByteArray &, data); EVENT_HANDLER1(void, _readed, PIByteArray &, data);
void internalDisconnect();
PIByteArray buff; PIByteArray buff;
PIMutex mutex_buff; PIMutex mutex_buff;
PIMutex mutex_connect; PIMutex mutex_connect;
PIConditionVariable cond_buff; PIConditionVariable cond_buff;
PIConditionVariable cond_connect; PIConditionVariable cond_connect;
std::atomic_bool is_connected; std::atomic_bool is_connected;
std::atomic_bool is_deleted;
}; };
#endif // PICLOUDCLIENT_H #endif // PICLOUDCLIENT_H

View File

@@ -78,6 +78,7 @@ private:
PIVector<Client *> clients_; PIVector<Client *> clients_;
PIMap<uint, Client *> index_clients; PIMap<uint, Client *> index_clients;
PITimer ping_timer;
mutable PIMutex clients_mutex; mutable PIMutex clients_mutex;
}; };

View File

@@ -25,6 +25,7 @@
#include "pip_cloud_export.h" #include "pip_cloud_export.h"
#include "pistring.h" #include "pistring.h"
#include "pimutex.h"
class PIEthernet; class PIEthernet;
@@ -52,6 +53,7 @@ public:
Connect = 1, Connect = 1,
Disconnect = 2, Disconnect = 2,
Data = 3, Data = 3,
Ping = 4,
}; };
TCP(PIStreamPacker * s); TCP(PIStreamPacker * s);
@@ -65,8 +67,9 @@ public:
void sendDisconnected(uint client_id); void sendDisconnected(uint client_id);
int sendData(const PIByteArray & data); int sendData(const PIByteArray & data);
int sendData(const PIByteArray & data, uint client_id); int sendData(const PIByteArray & data, uint client_id);
void sendPing();
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba); PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba);
PIByteArray parseData(PIByteArray & ba); bool canParseData(PIByteArray & ba);
PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba); PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba);
PIByteArray parseConnect_d(PIByteArray & ba); PIByteArray parseConnect_d(PIByteArray & ba);
uint parseConnect(PIByteArray & ba); uint parseConnect(PIByteArray & ba);
@@ -84,6 +87,8 @@ private:
PIByteArray suuid; PIByteArray suuid;
PIString server_name; PIString server_name;
PIStreamPacker * streampacker; PIStreamPacker * streampacker;
PIMutex mutex_send;
}; };
} }

View File

@@ -37,6 +37,14 @@ int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
} }
PIVariantTypes::Enum PICodeInfo::EnumInfo::toPIVariantEnum() {
PIVariantTypes::Enum en(name);
for (auto m: members) en << m.toPIVariantEnumerator();
if (!en.isEmpty()) en.selectValue(members.front().value);
return en;
}
PIMap<PIString, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo; PIMap<PIString, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
PIMap<PIString, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo; PIMap<PIString, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
PIMap<PIString, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions; PIMap<PIString, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;

View File

@@ -25,6 +25,8 @@
#define PICODEINFO_H #define PICODEINFO_H
#include "pistringlist.h" #include "pistringlist.h"
#include "pivarianttypes.h"
class PIVariant; class PIVariant;
@@ -77,6 +79,7 @@ struct PIP_EXPORT ClassInfo {
struct PIP_EXPORT EnumeratorInfo { struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIString & n = PIString(), int v = 0) {name = n; value = v;} EnumeratorInfo(const PIString & n = PIString(), int v = 0) {name = n; value = v;}
PIVariantTypes::Enumerator toPIVariantEnumerator() {return PIVariantTypes::Enumerator(value, name);}
MetaMap meta; MetaMap meta;
PIString name; PIString name;
int value; int value;
@@ -85,6 +88,7 @@ struct PIP_EXPORT EnumeratorInfo {
struct PIP_EXPORT EnumInfo { struct PIP_EXPORT EnumInfo {
PIString memberName(int value) const; PIString memberName(int value) const;
int memberValue(const PIString & name) const; int memberValue(const PIString & name) const;
PIVariantTypes::Enum toPIVariantEnum();
MetaMap meta; MetaMap meta;
PIString name; PIString name;
PIVector<PICodeInfo::EnumeratorInfo> members; PIVector<PICodeInfo::EnumeratorInfo> members;

View File

@@ -190,10 +190,39 @@ void PICodeParser::clear() {
piForeachC (PIString & d, defs) piForeachC (PIString & d, defs)
defines << Define(d, ""); defines << Define(d, "");
defines << Define(PIStringAscii("PICODE"), "") << custom_defines; defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent")
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"), "", PIStringList() << "name" << "parent")
<< Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name")
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PRIVATE_DECLARATION"))
<< Macro(PIStringAscii("EVENT" ), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT1"), "void name(a0 n0);", PIStringList() << "name" << "a0" << "n0")
<< Macro(PIStringAscii("EVENT2"), "void name(a0 n0, a1 n1);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1")
<< Macro(PIStringAscii("EVENT3"), "void name(a0 n0, a1 n1, a2 n2);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
<< Macro(PIStringAscii("EVENT4"), "void name(a0 n0, a1 n1, a2 n2, a3 n3);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
<< Macro(PIStringAscii("EVENT_HANDLER" ), "ret name()", PIStringList() << "ret" << "name")
<< Macro(PIStringAscii("EVENT_HANDLER0"), "ret name()", PIStringList() << "ret" << "name")
<< Macro(PIStringAscii("EVENT_HANDLER1"), "ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
<< Macro(PIStringAscii("EVENT_HANDLER2"), "ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
<< Macro(PIStringAscii("EVENT_HANDLER3"), "ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
<< Macro(PIStringAscii("EVENT_HANDLER4"), "ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
<< Macro(PIStringAscii("EVENT_VHANDLER" ), "virtual ret name()", PIStringList() << "ret" << "name")
<< Macro(PIStringAscii("EVENT_VHANDLER0"), "virtual ret name()", PIStringList() << "ret" << "name")
<< Macro(PIStringAscii("EVENT_VHANDLER1"), "virtual ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0")
<< Macro(PIStringAscii("EVENT_VHANDLER2"), "virtual ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1")
<< Macro(PIStringAscii("EVENT_VHANDLER3"), "virtual ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2")
<< Macro(PIStringAscii("EVENT_VHANDLER4"), "virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3")
;
} }
bool PICodeParser::parseFileContent(PIString & fc, bool main) { bool PICodeParser::parseFileContent(PIString & fc, bool main) {
static const PIString s_ns = PIStringAscii("::");
static const PIString s_bo = PIStringAscii("{\n"); static const PIString s_bo = PIStringAscii("{\n");
static const PIString s_bc = PIStringAscii("\n}\n"); static const PIString s_bc = PIStringAscii("\n}\n");
static const PIString s_class = PIStringAscii("class"); static const PIString s_class = PIStringAscii("class");
@@ -280,7 +309,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
replaceMeta(pfc); replaceMeta(pfc);
//piCout << NewLine << "file" << cur_file << pfc; //piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
int pl = -1; int pl = -1;
while (!pfc.isEmpty()) { while (!pfc.isEmpty()) {
pfc.trim(); pfc.trim();
@@ -288,7 +317,12 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (pl == nl) break; if (pl == nl) break;
pl = nl; pl = nl;
if (pfc.left(9) == s_namespace) { if (pfc.left(9) == s_namespace) {
pfc.cutLeft(pfc.find('{') + 1); pfc.cutLeft(9);
PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += pfc.takeCWord() + s_ns;
ccmn = pfc.takeRange('{', '}');
parseClass(0, ccmn);
cur_namespace = prev_namespace;
continue; continue;
} }
if (pfc.left(8) == s_template) { if (pfc.left(8) == s_template) {
@@ -417,7 +451,7 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
int ps = -1; int ps = -1;
bool def = false; bool def = false;
PIString prev_namespace = cur_namespace, stmp; PIString prev_namespace = cur_namespace, stmp;
cur_namespace = ce->name + s_ns; cur_namespace += ce->name + s_ns;
//piCout << "parse class" << ce->name << "namespace" << cur_namespace; //piCout << "parse class" << ce->name << "namespace" << cur_namespace;
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace; //piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
@@ -1074,9 +1108,19 @@ bool PICodeParser::parseDirective(PIString d) {
if (mname == s_PIMETA) return true; if (mname == s_PIMETA) return true;
if (d.left(1) == PIChar('(')) { // macro if (d.left(1) == PIChar('(')) { // macro
PIStringList args = d.takeRange('(', ')').split(',').trim(); PIStringList args = d.takeRange('(', ')').split(',').trim();
for (int i = 0; i < macros.size_s(); ++i)
if (macros[i].name == mname) {
macros.remove(i);
break;
}
macros << Macro(mname, d.trim(), args); macros << Macro(mname, d.trim(), args);
} else { // define } else { // define
d.trim(); d.trim();
for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) {
defines.remove(i);
break;
}
defines << Define(mname, d); defines << Define(mname, d);
evaluator.setVariable(mname, complexd_1); evaluator.setVariable(mname, complexd_1);
} }

View File

@@ -21,6 +21,7 @@
#ifndef WINDOWS #ifndef WINDOWS
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
#endif #endif

View File

@@ -25,7 +25,7 @@
#include "pithread.h" #include "pithread.h"
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); #define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); // TODO: rewrite with condvar
class PIP_EXPORT PIKbdListener: public PIThread class PIP_EXPORT PIKbdListener: public PIThread

View File

@@ -53,7 +53,7 @@ public:
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, f); resize(pid_size, f);
} }
inline PIDeque(size_t piv_size, std::function<T(size_t)> f): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(size_t piv_size, std::function<T(size_t i)> f): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f); resize(piv_size, f);
} }
@@ -174,6 +174,20 @@ public:
inline size_t capacity() const {return pid_rsize;} inline size_t capacity() const {return pid_rsize;}
inline size_t _start() const {return pid_start;} inline size_t _start() const {return pid_start;}
inline bool isEmpty() const {return (pid_size == 0);} inline bool isEmpty() const {return (pid_size == 0);}
inline bool isNotEmpty() const {return (pid_size > 0);}
inline bool any(std::function<bool(const T & e)> test) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) return true;
}
return false;
}
inline bool every(std::function<bool(const T & e)> test) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (!test(pid_data[i])) return false;
}
return true;
}
inline T & operator [](size_t index) {return pid_data[pid_start + index];} inline T & operator [](size_t index) {return pid_data[pid_start + index];}
inline const T & operator [](size_t index) const {return pid_data[pid_start + index];} inline const T & operator [](size_t index) const {return pid_data[pid_start + index];}
@@ -182,48 +196,102 @@ public:
inline const T & back() const {return pid_data[pid_start + pid_size - 1];} inline const T & back() const {return pid_data[pid_start + pid_size - 1];}
inline T & front() {return pid_data[pid_start];} inline T & front() {return pid_data[pid_start];}
inline const T & front() const {return pid_data[pid_start];} inline const T & front() const {return pid_data[pid_start];}
inline bool operator ==(const PIDeque<T> & t) const { inline bool operator ==(const PIDeque<T> & v) const {
if (pid_size != t.pid_size) return false; if (pid_size != v.pid_size) return false;
for (size_t i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i) {
if (t[i] != (*this)[i]) if (v[i] != (*this)[i]) {
return false; return false;
}
}
return true; return true;
} }
inline bool operator !=(const PIDeque<T> & t) const {return !(*this == t);} inline bool operator !=(const PIDeque<T> & v) const {return !(*this == v);}
inline bool operator >(const PIDeque<T> & t) const { inline bool operator <(const PIDeque<T> & v) const {
if (pid_size != t.pid_size) return pid_size > t.pid_size; if (pid_size != v.pid_size) return pid_size < v.pid_size;
for (size_t i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i) {
if (t[i] != (*this)[i]) return t[i] > (*this)[i]; if ((*this)[i] != v[i]) return (*this)[i] < v[i];
}
return false; return false;
} }
inline bool contains(const T & v) const { inline bool operator >(const PIDeque<T> & v) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) if (pid_size != v.pid_size) return pid_size > v.pid_size;
if (v == pid_data[i]) for (size_t i = 0; i < pid_size; ++i) {
if ((*this)[i] != v[i]) return (*this)[i] > v[i];
}
return false;
}
inline bool contains(const T & e) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) {
return true; return true;
}
}
return false; return false;
} }
inline int etries(const T & v) const { inline int etries(const T & e, size_t start = 0) const {
int ec = 0; int ec = 0;
for (size_t i = pid_start; i < pid_start + pid_size; ++i) if (start >= pid_size) return ec;
if (v == pid_data[i]) ++ec; for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) ++ec;
}
return ec; return ec;
} }
inline ssize_t indexOf(const T & v) const { inline int etries(std::function<bool(const T & e)> test, size_t start = 0) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) int ec = 0;
if (v == pid_data[i]) if (start >= pid_size) return ec;
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) ++ec;
}
return ec;
}
inline ssize_t indexOf(const T & e, size_t start = 0) const {
if (start >= pid_size) return -1;
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) {
return i - pid_start; return i - pid_start;
}
}
return -1; return -1;
} }
inline ssize_t lastIndexOf(const T & v) const { inline ssize_t indexWhere(std::function<bool(const T & e)> test, size_t start = 0) const {
for (ssize_t i = pid_start + (ssize_t)pid_size - 1; i >= pid_start; --i) if (start >= pid_size) return -1;
if (v == pid_data[i]) for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) {
return i - pid_start; return i - pid_start;
}
}
return -1;
}
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start < 0) start = pid_size - 1;
else start = piMin<ssize_t>(pid_size - 1, start);
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
if (e == pid_data[i]) {
return i - pid_start;
}
}
return -1;
}
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
if (start < 0) start = pid_size - 1;
else start = piMin<ssize_t>(pid_size - 1, start);
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
if (test(pid_data[i])) {
return i - pid_start;
}
}
return -1; return -1;
} }
inline T * data(size_t index = 0) {return &(pid_data[pid_start + index]);} inline T * data(size_t index = 0) {return &(pid_data[pid_start + index]);}
inline const T * data(size_t index = 0) const {return &(pid_data[pid_start + index]);} inline const T * data(size_t index = 0) const {return &(pid_data[pid_start + index]);}
PIDeque<T> getRange(size_t index, size_t count) const {
if (index >= pid_size || count == 0) return PIDeque<T>();
if (index + count > pid_size) count = pid_size - index;
return PIDeque(&(pid_data[pid_start + index]), count);
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -244,15 +312,17 @@ public:
inline PIDeque<T> & fill(const T & f = T()) { inline PIDeque<T> & fill(const T & f = T()) {
deleteT(pid_data + pid_start, pid_size); deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, pid_size) PIINTROSPECTION_CONTAINER_USED(T, pid_size)
for (size_t i = pid_start; i < pid_start + pid_size; ++i) for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
elementNew(pid_data + i, f); elementNew(pid_data + i, f);
}
return *this; return *this;
} }
inline PIDeque<T> & fill(std::function<T(size_t)> f) { inline PIDeque<T> & fill(std::function<T(size_t i)> f) {
deleteT(pid_data + pid_start, pid_size); deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, pid_size) PIINTROSPECTION_CONTAINER_USED(T, pid_size)
for (size_t i = pid_start; i < pid_start + pid_size; ++i) for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
elementNew(pid_data + i, f(i)); elementNew(pid_data + i, f(i));
}
return *this; return *this;
} }
inline PIDeque<T> & assign(const T & f = T()) {return fill(f);} inline PIDeque<T> & assign(const T & f = T()) {return fill(f);}
@@ -275,32 +345,36 @@ public:
if (new_size < pid_size) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2; pid_start = (pid_rsize - pid_size) / 2;
} }
}
if (new_size > pid_size) { if (new_size > pid_size) {
size_t os = pid_size; size_t os = pid_size;
alloc(new_size, true); alloc(new_size, true);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f); elementNew(pid_data + i, f);
} }
}
return *this; return *this;
} }
inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t)> f) { inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size < pid_size) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2; pid_start = (pid_rsize - pid_size) / 2;
} }
}
if (new_size > pid_size) { if (new_size > pid_size) {
size_t os = pid_size; size_t os = pid_size;
alloc(new_size, true); alloc(new_size, true);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f(i)); elementNew(pid_data + i, f(i));
} }
}
return *this; return *this;
} }
@@ -326,8 +400,8 @@ public:
return *this; return *this;
} }
inline PIDeque<T> & insert(size_t index, const T & v = T()) { inline PIDeque<T> & insert(size_t index, const T & e = T()) {
if (index == pid_size) return push_back(v); if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
@@ -338,14 +412,15 @@ public:
} }
} else { } else {
alloc(pid_size + 1, false, -1); alloc(pid_size + 1, false, -1);
if (index > 0) if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T)); memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
} }
elementNew(pid_data + pid_start + index, v); }
elementNew(pid_data + pid_start + index, e);
return *this; return *this;
} }
inline PIDeque<T> & insert(size_t index, T && v) { inline PIDeque<T> & insert(size_t index, T && e) {
if (index == pid_size) return push_back(v); if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
@@ -356,10 +431,11 @@ public:
} }
} else { } else {
alloc(pid_size + 1, false, -1); alloc(pid_size + 1, false, -1);
if (index > 0) if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T)); memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
} }
elementNew(pid_data + pid_start + index, std::move(v)); }
elementNew(pid_data + pid_start + index, std::move(e));
return *this; return *this;
} }
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) { inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
@@ -369,13 +445,15 @@ public:
if (dir) { if (dir) {
ssize_t os = pid_size - index; ssize_t os = pid_size - index;
alloc(pid_size + other.pid_size, true); alloc(pid_size + other.pid_size, true);
if (os > 0) if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start + other.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T)); memmove((void*)(&(pid_data[index + pid_start + other.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else { } else {
alloc(pid_size + other.pid_size, false, -other.pid_size); alloc(pid_size + other.pid_size, false, -other.pid_size);
if (index > 0) if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + other.pid_size])), index * sizeof(T)); memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + other.pid_size])), index * sizeof(T));
} }
}
newT(pid_data + pid_start + index, other.pid_data + other.pid_start, other.pid_size); newT(pid_data + pid_start + index, other.pid_data + other.pid_start, other.pid_size);
return *this; return *this;
} }
@@ -389,9 +467,13 @@ public:
size_t os = pid_size - index - count; size_t os = pid_size - index - count;
deleteT(&(pid_data[index + pid_start]), count); deleteT(&(pid_data[index + pid_start]), count);
if (os <= index) { if (os <= index) {
if (os > 0) memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T)); if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
}
} else { } else {
if (index > 0) memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T)); if (index > 0) {
memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
}
pid_start += count; pid_start += count;
} }
pid_size -= count; pid_size -= count;
@@ -419,88 +501,114 @@ public:
return *this; return *this;
} }
inline PIDeque<T> & removeOne(const T & v) { inline PIDeque<T> & removeOne(const T & e) {
for (size_t i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i) {
if (pid_data[i + pid_start] == v) { if (pid_data[i + pid_start] == e) {
remove(i); remove(i);
return *this; return *this;
} }
}
return *this; return *this;
} }
inline PIDeque<T> & removeAll(const T & v) { inline PIDeque<T> & removeAll(const T & e) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (pid_data[i + pid_start] == v) { if (pid_data[i + pid_start] == e) {
remove(i); remove(i);
--i; --i;
} }
}
return *this;
}
inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (test(pid_data[i + pid_start])) {
remove(i);
--i;
}
}
return *this; return *this;
} }
inline PIDeque<T> & push_back(const T & v) { inline PIDeque<T> & push_back(const T & e) {
alloc(pid_size + 1, true); alloc(pid_size + 1, true);
PIINTROSPECTION_CONTAINER_USED(T, 1); PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, v); elementNew(pid_data + pid_start + pid_size - 1, e);
return *this; return *this;
} }
inline PIDeque<T> & push_back(T && v) { inline PIDeque<T> & push_back(T && e) {
alloc(pid_size + 1, true); alloc(pid_size + 1, true);
PIINTROSPECTION_CONTAINER_USED(T, 1); PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, std::move(v)); elementNew(pid_data + pid_start + pid_size - 1, std::move(e));
return *this; return *this;
} }
inline PIDeque<T> & append(const T & v) {return push_back(v);} inline PIDeque<T> & append(const T & e) {return push_back(e);}
inline PIDeque<T> & append(T && v) {return push_back(std::move(v));} inline PIDeque<T> & append(T && e) {return push_back(std::move(e));}
inline PIDeque<T> & append(const PIDeque<T> & t) { inline PIDeque<T> & append(const PIDeque<T> & v) {
assert(&t != this); assert(&v != this);
size_t ps = pid_size; size_t ps = pid_size;
alloc(pid_size + t.pid_size, true); alloc(pid_size + v.pid_size, true);
newT(pid_data + ps + pid_start, t.pid_data + t.pid_start, t.pid_size); newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size);
return *this; return *this;
} }
inline PIDeque<T> & operator <<(const T & v) {return push_back(v);} inline PIDeque<T> & operator <<(const T & e) {return push_back(e);}
inline PIDeque<T> & operator <<(T && v) {return push_back(std::move(v));} inline PIDeque<T> & operator <<(T && e) {return push_back(std::move(e));}
inline PIDeque<T> & operator <<(const PIDeque<T> & t) {return append(t);} inline PIDeque<T> & operator <<(const PIDeque<T> & v) {return append(v);}
inline PIDeque<T> & push_front(const T & v) {insert(0, v); return *this;} inline PIDeque<T> & push_front(const T & e) {insert(0, e); return *this;}
inline PIDeque<T> & push_front(T && v) {insert(0, std::move(v)); return *this;} inline PIDeque<T> & push_front(T && e) {insert(0, std::move(e)); return *this;}
inline PIDeque<T> & prepend(const T & v) {return push_front(v);} inline PIDeque<T> & prepend(const T & e) {return push_front(e);}
inline PIDeque<T> & prepend(T && v) {return push_front(std::move(v));} inline PIDeque<T> & prepend(T && e) {return push_front(std::move(e));}
inline PIDeque<T> & pop_back() {if (pid_size == 0) return *this; resize(pid_size - 1); return *this;} inline PIDeque<T> & pop_back() {if (pid_size == 0) return *this; resize(pid_size - 1); return *this;}
inline PIDeque<T> & pop_front() {if (pid_size == 0) return *this; remove(0); return *this;} inline PIDeque<T> & pop_front() {if (pid_size == 0) return *this; remove(0); return *this;}
inline T take_back() {T t(back()); pop_back(); return t;} inline T take_back() {T e(back()); pop_back(); return e;}
inline T take_front() {T t(front()); pop_front(); return t;} inline T take_front() {T e(front()); pop_front(); return e;}
template <typename ST> template <typename ST>
PIDeque<ST> toType() const { PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size); PIDeque<ST> ret(pid_size);
for (uint i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i) {
ret[i] = ST(pid_data[i + pid_start]); ret[i] = ST(pid_data[i + pid_start]);
}
return ret; return ret;
} }
const PIDeque<T> & forEach(std::function<void(const T &)> f) const { const PIDeque<T> & forEach(std::function<void(const T & e)> f) const {
for (uint i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i) {
f(pid_data[i + pid_start]); f(pid_data[i + pid_start]);
}
return *this; return *this;
} }
PIDeque<T> copyForEach(std::function<T(const T &)> f) const { PIDeque<T> copyForEach(std::function<T(const T & e)> f) const {
PIDeque<T> ret; ret.reserve(pid_size); PIDeque<T> ret; ret.reserve(pid_size);
for (uint i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i) {
ret << f(pid_data[i + pid_start]); ret << f(pid_data[i + pid_start]);
}
return ret; return ret;
} }
PIDeque<T> & forEachInplace(std::function<T(const T &)> f) { PIDeque<T> & forEachInplace(std::function<T(const T & e)> f) {
for (uint i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i)
pid_data[i + pid_start] = f(pid_data[i + pid_start]); pid_data[i + pid_start] = f(pid_data[i + pid_start]);
return *this; return *this;
} }
template <typename ST> template <typename ST>
PIDeque<ST> toType(std::function<ST(const T &)> f) const { PIDeque<ST> map(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret; ret.reserve(pid_size); PIDeque<ST> ret; ret.reserve(pid_size);
for (uint i = 0; i < pid_size; ++i) for (size_t i = 0; i < pid_size; ++i) {
ret << f(pid_data[i + pid_start]); ret << f(pid_data[i + pid_start]);
}
return ret;
}
template <typename ST>
PIDeque<ST> toType(std::function<ST(const T & e)> f) const {return map(f);}
template <typename ST>
ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < pid_size; ++i) {
ret = f(pid_data[i + pid_start], ret);
}
return ret; return ret;
} }
@@ -510,16 +618,18 @@ public:
assert(rows*cols == pid_size); assert(rows*cols == pid_size);
ret.resize(rows); ret.resize(rows);
if (order == byRow) { if (order == byRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols); ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols);
} }
}
if (order == byColumn) { if (order == byColumn) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols); ret[r].resize(cols);
for (size_t c = 0; c < cols; c++) for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c*rows + r]; ret[r][c] = pid_data[c*rows + r];
} }
} }
}
return ret; return ret;
} }
@@ -533,14 +643,17 @@ public:
size_t cols = at(0).size(); size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == byRow) { if (order == byRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret.append(at(r)); ret.append(at(r));
} }
}
if (order == byColumn) { if (order == byColumn) {
for (size_t c = 0; c < cols; c++) for (size_t c = 0; c < cols; c++) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret << at(r)[c]; ret << at(r)[c];
} }
}
}
ret.resize(rows * cols); ret.resize(rows * cols);
return ret; return ret;
} }
@@ -549,11 +662,13 @@ private:
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;} inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
inline size_t asize(ssize_t s) { inline size_t asize(ssize_t s) {
if (s <= 0) return 0; if (s <= 0) return 0;
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) {
return pid_rsize + pid_rsize; return pid_rsize + pid_rsize;
}
ssize_t t = 0, s_ = s - 1; ssize_t t = 0, s_ = s - 1;
while (s_ >> t) while (s_ >> t) {
++t; ++t;
}
return (1 << t); return (1 << t);
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
@@ -577,10 +692,11 @@ private:
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) { if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
} }
} }
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -652,10 +768,11 @@ private:
} }
} else { } else {
size_t as; size_t as;
if (pid_start + start_offset < 0) if (pid_start + start_offset < 0) {
as = asize(pid_rsize - start_offset); as = asize(pid_rsize - start_offset);
else as = pid_rsize; } else {
as = pid_rsize;
}
if (as > pid_rsize) { if (as > pid_rsize) {
T * td = (T*)(malloc(as * sizeof(T))); T * td = (T*)(malloc(as * sizeof(T)));
ssize_t ns = pid_start + as - pid_rsize; ssize_t ns = pid_start + as - pid_rsize;
@@ -682,7 +799,15 @@ private:
#ifdef PIP_STD_IOSTREAM #ifdef PIP_STD_IOSTREAM
template<typename T> template<typename T>
inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;} inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
return s;
}
#endif #endif
template<typename T> template<typename T>
@@ -692,8 +817,7 @@ inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s << "{"; s << "{";
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
s << v[i]; s << v[i];
if (i < v.size() - 1) if (i < v.size() - 1) s << ", ";
s << ", ";
} }
s << "}"; s << "}";
s.restoreControl(); s.restoreControl();

View File

@@ -107,6 +107,7 @@ public:
iterator(): parent(0), pos(0) {} iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);} const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);} T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
inline PIPair<Key, T> operator *() const {return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));}
void operator ++() {++pos;} void operator ++() {++pos;}
void operator ++(int) {++pos;} void operator ++(int) {++pos;}
void operator --() {--pos;} void operator --() {--pos;}
@@ -125,6 +126,7 @@ public:
reverse_iterator(): parent(0), pos(0) {} reverse_iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);} const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);} T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
inline PIPair<Key, T> operator *() const {return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));}
void operator ++() {--pos;} void operator ++() {--pos;}
void operator ++(int) {--pos;} void operator ++(int) {--pos;}
void operator --() {++pos;} void operator --() {++pos;}

View File

@@ -33,6 +33,7 @@ template<typename Type0, typename Type1>
class PIPair { class PIPair {
public: public:
PIPair() {first = Type0(); second = Type1();} PIPair() {first = Type0(); second = Type1();}
PIPair(std::tuple<Type0, Type1> tuple) {first = std::get<0>(tuple); second = std::get<1>(tuple);}
PIPair(const Type0 & value0, const Type1 & value1) {first = value0; second = value1;} PIPair(const Type0 & value0, const Type1 & value1) {first = value0; second = value1;}
Type0 first; Type0 first;
Type1 second; Type1 second;

View File

@@ -39,10 +39,10 @@ public:
alloc(size); alloc(size);
newT(piv_data, data, piv_size); newT(piv_data, data, piv_size);
} }
inline PIVector(const PIVector<T> & other): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector(const PIVector<T> & v): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(other.piv_size); alloc(v.piv_size);
newT(piv_data, other.piv_data, piv_size); newT(piv_data, v.piv_data, piv_size);
} }
inline PIVector(std::initializer_list<T> init_list): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector(std::initializer_list<T> init_list): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
@@ -53,13 +53,13 @@ public:
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f); resize(piv_size, f);
} }
inline PIVector(size_t piv_size, std::function<T(size_t)> f): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector(size_t piv_size, std::function<T(size_t i)> f): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f); resize(piv_size, f);
} }
inline PIVector(PIVector<T> && other): piv_data(other.piv_data), piv_size(other.piv_size), piv_rsize(other.piv_rsize) { inline PIVector(PIVector<T> && v): piv_data(v.piv_data), piv_size(v.piv_size), piv_rsize(v.piv_rsize) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
other._reset(); v._reset();
} }
inline virtual ~PIVector() { inline virtual ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
@@ -69,17 +69,17 @@ public:
_reset(); _reset();
} }
inline PIVector<T> & operator =(const PIVector<T> & other) { inline PIVector<T> & operator =(const PIVector<T> & v) {
if (this == &other) return *this; if (this == &v) return *this;
clear(); clear();
deleteT(piv_data, piv_size); deleteT(piv_data, piv_size);
alloc(other.piv_size); alloc(v.piv_size);
newT(piv_data, other.piv_data, piv_size); newT(piv_data, v.piv_data, piv_size);
return *this; return *this;
} }
inline PIVector<T> & operator =(PIVector<T> && other) { inline PIVector<T> & operator =(PIVector<T> && v) {
swap(other); swap(v);
return *this; return *this;
} }
@@ -174,6 +174,19 @@ public:
inline size_t length() const {return piv_size;} inline size_t length() const {return piv_size;}
inline size_t capacity() const {return piv_rsize;} inline size_t capacity() const {return piv_rsize;}
inline bool isEmpty() const {return (piv_size == 0);} inline bool isEmpty() const {return (piv_size == 0);}
inline bool isNotEmpty() const {return (piv_size > 0);}
inline bool any(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < piv_size; ++i) {
if (test(piv_data[i])) return true;
}
return false;
}
inline bool every(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < piv_size; ++i) {
if (!test(piv_data[i])) return false;
}
return true;
}
inline T & operator [](size_t index) {return piv_data[index];} inline T & operator [](size_t index) {return piv_data[index];}
inline const T & operator [](size_t index) const {return piv_data[index];} inline const T & operator [](size_t index) const {return piv_data[index];}
@@ -183,42 +196,103 @@ public:
inline T & front() {return piv_data[0];} inline T & front() {return piv_data[0];}
inline const T & front() const {return piv_data[0];} inline const T & front() const {return piv_data[0];}
inline bool operator ==(const PIVector<T> & t) const { inline bool operator ==(const PIVector<T> & t) const {
if (piv_size != t.piv_size) if (piv_size != t.piv_size) {
return false; return false;
for (size_t i = 0; i < piv_size; ++i) }
if (t[i] != piv_data[i]) for (size_t i = 0; i < piv_size; ++i) {
if (t[i] != piv_data[i]) {
return false; return false;
}
}
return true; return true;
} }
inline bool operator !=(const PIVector<T> & t) const {return !(*this == t);} inline bool operator !=(const PIVector<T> & t) const {return !(*this == t);}
inline bool contains(const T & v) const { inline bool operator <(const PIVector<T> & t) const {
for (size_t i = 0; i < piv_size; ++i) if (piv_size != t.piv_size) return piv_size < t.piv_size;
if (v == piv_data[i]) for (size_t i = 0; i < piv_size; ++i) {
return true; if ((*this)[i] != t[i]) return (*this)[i] < t[i];
}
return false; return false;
} }
inline int etries(const T & v) const { inline bool operator >(const PIVector<T> & t) const {
if (piv_size != t.piv_size) return piv_size > t.piv_size;
for (size_t i = 0; i < piv_size; ++i) {
if ((*this)[i] != t[i]) return (*this)[i] > t[i];
}
return false;
}
inline bool contains(const T & e) const {
for (size_t i = 0; i < piv_size; ++i) {
if (e == piv_data[i]) {
return true;
}
}
return false;
}
inline int etries(const T & e, size_t start = 0) const {
int ec = 0; int ec = 0;
for (size_t i = 0; i < piv_size; ++i) if (start >= piv_size) return ec;
if (v == piv_data[i]) ++ec; for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) ++ec;
}
return ec; return ec;
} }
inline ssize_t indexOf(const T & v) const { inline int etries(std::function<bool(const T & e)> test, size_t start = 0) const {
for (size_t i = 0; i < piv_size; ++i) int ec = 0;
if (v == piv_data[i]) if (start >= piv_size) return ec;
for (size_t i = start; i < piv_size; ++i) {
if (test(piv_data[i])) ++ec;
}
return ec;
}
inline ssize_t indexOf(const T & e, size_t start = 0) const {
if (start >= piv_size) return -1;
for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) {
return i; return i;
}
}
return -1; return -1;
} }
inline ssize_t lastIndexOf(const T & v) const { inline ssize_t indexWhere(std::function<bool(const T & e)> test, size_t start = 0) const {
for (ssize_t i = piv_size - 1; i >= 0; --i) if (start >= piv_size) return -1;
if (v == piv_data[i]) for (size_t i = start; i < piv_size; ++i) {
if (test(piv_data[i])) {
return i; return i;
}
}
return -1;
}
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start < 0) start = piv_size - 1;
else start = piMin<ssize_t>(piv_size - 1, start);
for (ssize_t i = start; i >= 0; --i) {
if (e == piv_data[i]) {
return i;
}
}
return -1;
}
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
if (start < 0) start = piv_size - 1;
else start = piMin<ssize_t>(piv_size - 1, start);
for (ssize_t i = start; i >= 0; --i) {
if (test(piv_data[i])) {
return i;
}
}
return -1; return -1;
} }
inline T * data(size_t index = 0) {return &(piv_data[index]);} inline T * data(size_t index = 0) {return &(piv_data[index]);}
inline const T * data(size_t index = 0) const {return &(piv_data[index]);} inline const T * data(size_t index = 0) const {return &(piv_data[index]);}
PIVector<T> getRange(size_t index, size_t count) const {
if (index >= piv_size || count == 0) return PIVector<T>();
if (index + count > piv_size) count = piv_size - index;
return PIVector(&(piv_data[index]), count);
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -238,15 +312,17 @@ public:
inline PIVector<T> & fill(const T & f = T()) { inline PIVector<T> & fill(const T & f = T()) {
deleteT(piv_data, piv_size); deleteT(piv_data, piv_size);
PIINTROSPECTION_CONTAINER_USED(T, piv_size) PIINTROSPECTION_CONTAINER_USED(T, piv_size)
for (size_t i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
elementNew(piv_data + i, f); elementNew(piv_data + i, f);
}
return *this; return *this;
} }
inline PIVector<T> & fill(std::function<T(size_t)> f) { inline PIVector<T> & fill(std::function<T(size_t i)> f) {
deleteT(piv_data, piv_size); deleteT(piv_data, piv_size);
PIINTROSPECTION_CONTAINER_USED(T, piv_size) PIINTROSPECTION_CONTAINER_USED(T, piv_size)
for (size_t i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
elementNew(piv_data + i, f(i)); elementNew(piv_data + i, f(i));
}
return *this; return *this;
} }
inline PIVector<T> & assign(const T & f = T()) {return fill(f);} inline PIVector<T> & assign(const T & f = T()) {return fill(f);}
@@ -275,12 +351,13 @@ public:
size_t os = piv_size; size_t os = piv_size;
alloc(new_size); alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i) for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f); elementNew(piv_data + i, f);
} }
}
return *this; return *this;
} }
inline PIVector<T> & resize(size_t new_size, std::function<T(size_t)> f) { inline PIVector<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size < piv_size) { if (new_size < piv_size) {
T * de = &(piv_data[new_size]); T * de = &(piv_data[new_size]);
deleteT(de, piv_size - new_size); deleteT(de, piv_size - new_size);
@@ -290,9 +367,10 @@ public:
size_t os = piv_size; size_t os = piv_size;
alloc(new_size); alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i) for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f(i)); elementNew(piv_data + i, f(i));
} }
}
return *this; return *this;
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
@@ -320,34 +398,35 @@ public:
return *this; return *this;
} }
inline PIVector<T> & insert(size_t index, const T & v = T()) { inline PIVector<T> & insert(size_t index, const T & e = T()) {
alloc(piv_size + 1); alloc(piv_size + 1);
if (index < piv_size - 1) { if (index < piv_size - 1) {
size_t os = piv_size - index - 1; size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
} }
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, v); elementNew(piv_data + index, e);
return *this; return *this;
} }
inline PIVector<T> & insert(size_t index, T && v) { inline PIVector<T> & insert(size_t index, T && e) {
alloc(piv_size + 1); alloc(piv_size + 1);
if (index < piv_size - 1) { if (index < piv_size - 1) {
size_t os = piv_size - index - 1; size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
} }
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, std::move(v)); elementNew(piv_data + index, std::move(e));
return *this; return *this;
} }
inline PIVector<T> & insert(size_t index, const PIVector<T> & other) { inline PIVector<T> & insert(size_t index, const PIVector<T> & v) {
if (other.isEmpty()) return *this; if (v.isEmpty()) return *this;
assert(&other != this); assert(&v != this);
ssize_t os = piv_size - index; ssize_t os = piv_size - index;
alloc(piv_size + other.piv_size); alloc(piv_size + v.piv_size);
if (os > 0) if (os > 0) {
memmove((void*)(&(piv_data[index + other.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove((void*)(&(piv_data[index + v.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
newT(piv_data + index, other.piv_data, other.piv_size); }
newT(piv_data + index, v.piv_data, v.piv_size);
return *this; return *this;
} }
@@ -364,10 +443,10 @@ public:
return *this; return *this;
} }
inline void swap(PIVector<T> & other) { inline void swap(PIVector<T> & v) {
piSwap<T*>(piv_data, other.piv_data); piSwap<T*>(piv_data, v.piv_data);
piSwap<size_t>(piv_size, other.piv_size); piSwap<size_t>(piv_size, v.piv_size);
piSwap<size_t>(piv_rsize, other.piv_rsize); piSwap<size_t>(piv_rsize, v.piv_rsize);
} }
typedef int (*CompareFunc)(const T * , const T * ); typedef int (*CompareFunc)(const T * , const T * );
@@ -384,98 +463,126 @@ public:
return *this; return *this;
} }
inline PIVector<T> & removeOne(const T & v) { inline PIVector<T> & removeOne(const T & e) {
for (size_t i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
if (piv_data[i] == v) { if (piv_data[i] == e) {
remove(i); remove(i);
return *this; return *this;
} }
}
return *this; return *this;
} }
inline PIVector<T> & removeAll(const T & v) { inline PIVector<T> & removeAll(const T & e) {
for (ssize_t i = 0; i < ssize_t(piv_size); ++i) for (ssize_t i = 0; i < ssize_t(piv_size); ++i) {
if (piv_data[i] == v) { if (piv_data[i] == e) {
remove(i); remove(i);
--i; --i;
} }
}
return *this;
}
inline PIVector<T> & removeWhere(std::function<bool(const T & e)> test) {
for (ssize_t i = 0; i < ssize_t(piv_size); ++i) {
if (test(piv_data[i])) {
remove(i);
--i;
}
}
return *this; return *this;
} }
inline PIVector<T> & push_back(const T & v) { inline PIVector<T> & push_back(const T & e) {
alloc(piv_size + 1); alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1); PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, v); elementNew(piv_data + piv_size - 1, e);
return *this; return *this;
} }
inline PIVector<T> & push_back(T && v) {
inline PIVector<T> & push_back(T && e) {
alloc(piv_size + 1); alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1); PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, std::move(v)); elementNew(piv_data + piv_size - 1, std::move(e));
return *this; return *this;
} }
inline PIVector<T> & append(const T & v) {return push_back(v);}
inline PIVector<T> & append(T && v) {return push_back(std::move(v));} inline PIVector<T> & append(const T & e) {return push_back(e);}
inline PIVector<T> & append(const PIVector<T> & other) { inline PIVector<T> & append(T && e) {return push_back(std::move(e));}
assert(&other != this); inline PIVector<T> & append(const PIVector<T> & v) {
assert(&v != this);
size_t ps = piv_size; size_t ps = piv_size;
alloc(piv_size + other.piv_size); alloc(piv_size + v.piv_size);
newT(piv_data + ps, other.piv_data, other.piv_size); newT(piv_data + ps, v.piv_data, v.piv_size);
return *this; return *this;
} }
inline PIVector<T> & operator <<(const T & v) {return push_back(v);} inline PIVector<T> & operator <<(const T & e) {return push_back(e);}
inline PIVector<T> & operator <<(T && v) {return push_back(std::move(v));} inline PIVector<T> & operator <<(T && e) {return push_back(std::move(e));}
inline PIVector<T> & operator <<(const PIVector<T> & other) {return append(other);} inline PIVector<T> & operator <<(const PIVector<T> & v) {return append(v);}
inline PIVector<T> & push_front(const T & v) {insert(0, v); return *this;} inline PIVector<T> & push_front(const T & e) {insert(0, e); return *this;}
inline PIVector<T> & push_front(T && v) {insert(0, std::move(v)); return *this;} inline PIVector<T> & push_front(T && e) {insert(0, std::move(e)); return *this;}
inline PIVector<T> & prepend(const T & v) {return push_front(v);} inline PIVector<T> & prepend(const T & e) {return push_front(e);}
inline PIVector<T> & prepend(T && v) {return push_front(std::move(v));} inline PIVector<T> & prepend(T && e) {return push_front(std::move(e));}
inline PIVector<T> & pop_back() { inline PIVector<T> & pop_back() {
if (piv_size == 0) if (piv_size == 0) return *this;
return *this;
resize(piv_size - 1); resize(piv_size - 1);
return *this; return *this;
} }
inline PIVector<T> & pop_front() { inline PIVector<T> & pop_front() {
if (piv_size == 0) if (piv_size == 0) return *this;
return *this;
remove(0); remove(0);
return *this; return *this;
} }
inline T take_back() {T t(back()); pop_back(); return t;} inline T take_back() {T e(back()); pop_back(); return e;}
inline T take_front() {T t(front()); pop_front(); return t;} inline T take_front() {T e(front()); pop_front(); return e;}
template <typename ST> template <typename ST>
PIVector<ST> toType() const { PIVector<ST> toType() const {
PIVector<ST> ret(piv_size); PIVector<ST> ret(piv_size);
for (uint i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
ret[i] = ST(piv_data[i]); ret[i] = ST(piv_data[i]);
}
return ret; return ret;
} }
const PIVector<T> & forEach(std::function<void(const T &)> f) const { const PIVector<T> & forEach(std::function<void(const T & e)> f) const {
for (uint i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
f(piv_data[i]); f(piv_data[i]);
}
return *this; return *this;
} }
PIVector<T> copyForEach(std::function<T(const T &)> f) const { PIVector<T> copyForEach(std::function<T(const T & e)> f) const {
PIVector<T> ret; ret.reserve(piv_size); PIVector<T> ret; ret.reserve(piv_size);
for (uint i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
ret << f(piv_data[i]); ret << f(piv_data[i]);
}
return ret; return ret;
} }
PIVector<T> & forEachInplace(std::function<T(const T &)> f) { PIVector<T> & forEachInplace(std::function<T(const T & e)> f) {
for (uint i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
piv_data[i] = f(piv_data[i]); piv_data[i] = f(piv_data[i]);
}
return *this; return *this;
} }
template <typename ST> template <typename ST>
PIVector<ST> toType(std::function<ST(const T &)> f) const { PIVector<ST> map(std::function<ST(const T & e)> f) const {
PIVector<ST> ret; ret.reserve(piv_size); PIVector<ST> ret; ret.reserve(piv_size);
for (uint i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
ret << f(piv_data[i]); ret << f(piv_data[i]);
}
return ret;
}
template <typename ST>
PIVector<ST> toType(std::function<ST(const T & e)> f) const {return map(f);}
template <typename ST>
ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < piv_size; ++i) {
ret = f(piv_data[i], ret);
}
return ret; return ret;
} }
@@ -485,16 +592,18 @@ public:
assert(rows*cols == piv_size); assert(rows*cols == piv_size);
ret.resize(rows); ret.resize(rows);
if (order == byRow) { if (order == byRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret[r] = PIVector<T>(&(piv_data[r*cols]), cols); ret[r] = PIVector<T>(&(piv_data[r*cols]), cols);
} }
}
if (order == byColumn) { if (order == byColumn) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols); ret[r].resize(cols);
for (size_t c = 0; c < cols; c++) for (size_t c = 0; c < cols; c++) {
ret[r][c] = piv_data[c*rows + r]; ret[r][c] = piv_data[c*rows + r];
} }
} }
}
return ret; return ret;
} }
@@ -508,14 +617,17 @@ public:
size_t cols = at(0).size(); size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == byRow) { if (order == byRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret.append(at(r)); ret.append(at(r));
} }
}
if (order == byColumn) { if (order == byColumn) {
for (size_t c = 0; c < cols; c++) for (size_t c = 0; c < cols; c++) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret << at(r)[c]; ret << at(r)[c];
} }
}
}
ret.resize(rows * cols); ret.resize(rows * cols);
return ret; return ret;
} }
@@ -524,8 +636,9 @@ private:
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;} inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
inline size_t asize(size_t s) { inline size_t asize(size_t s) {
if (s == 0) return 0; if (s == 0) return 0;
if (piv_rsize + piv_rsize >= s && piv_rsize < s) if (piv_rsize + piv_rsize >= s && piv_rsize < s) {
return piv_rsize + piv_rsize; return piv_rsize + piv_rsize;
}
ssize_t t = 0, s_ = s - 1; ssize_t t = 0, s_ = s - 1;
while (s_ >> t) ++t; while (s_ >> t) ++t;
return (1 << t); return (1 << t);
@@ -551,10 +664,11 @@ private:
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) { if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
} }
} }
}
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -612,7 +726,15 @@ private:
#ifdef PIP_STD_IOSTREAM #ifdef PIP_STD_IOSTREAM
template<typename T> template<typename T>
inline std::ostream & operator <<(std::ostream & s, const PIVector<T> & v) {s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;} inline std::ostream & operator <<(std::ostream & s, const PIVector<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
return s;
}
#endif #endif
template<typename T> template<typename T>
@@ -622,9 +744,10 @@ inline PICout operator <<(PICout s, const PIVector<T> & v) {
s << "{"; s << "{";
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
s << v[i]; s << v[i];
if (i < v.size() - 1) if (i < v.size() - 1) {
s << ", "; s << ", ";
} }
}
s << "}"; s << "}";
s.restoreControl(); s.restoreControl();
return s; return s;

View File

@@ -1,8 +1,15 @@
/*! @file pibase.h /*! @file pibase.h
* @brief Base types and functions * \brief
* \~english Base types and functions
* \~russian Базовые типы и методы
* *
* \details
* \~english
* This file implements first layer above the system and * This file implements first layer above the system and
* declares some basic useful functions * declares some basic useful functions
* \~russian
* Этот файл реализует первый слой после системы и объявляет
* несколько базовых полезных методов
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -31,88 +38,145 @@
#include "pip_export.h" #include "pip_export.h"
#include "pip_defs.h" #include "pip_defs.h"
#include "string.h" #include "string.h"
#include <limits>
//! \~english
//! Meta-information section for any entity. //! Meta-information section for any entity.
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo. //! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
//! Contains sequence of key=value pairs, e.g. //! Contains sequence of key=value pairs, e.g.
//! \~russian
//! Секция метаинформации для любой сущности.
//! Парсится \a pip_cmg и доступна с помощью \a PICodeInfo.
//! Содержит набор пар ключ=значение, например
//! \~
//! PIMETA(id=12345,tag="my string") //! PIMETA(id=12345,tag="my string")
#define PIMETA(...) #define PIMETA(...)
#ifdef DOXYGEN #ifdef DOXYGEN
//! Major value of PIP version //! \brief
//! \~english Major value of PIP version
//! \~russian Мажорная версия PIP
# define PIP_VERSION_MAJOR # define PIP_VERSION_MAJOR
//! Minor value of PIP version //! \brief
//! \~english Minor value of PIP version
//! \~russian Минорная версия PIP
# define PIP_VERSION_MINOR # define PIP_VERSION_MINOR
//! Revision value of PIP version //! \brief
//! \~english Revision value of PIP version
//! \~russian Ревизия версии PIP
# define PIP_VERSION_REVISION # define PIP_VERSION_REVISION
//! Suffix of PIP version //! \brief
//! \~english Suffix of PIP version
//! \~russian Суффикс версии PIP
# define PIP_VERSION_SUFFIX # define PIP_VERSION_SUFFIX
//! Version of PIP in hex - 0x##(Major)##(Minor)##(Revision) //! \brief
//! \~english Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
//! \~russian Версия PIP в hex - 0x##(Major)##(Minor)##(Revision)
# define PIP_VERSION # define PIP_VERSION
//! Macro is defined when compile-time debug is enabled //! \brief
//! \~english Macro is defined when compile-time debug is enabled
//! \~russian Макрос объявлен когда включена compile-time отладка
# define PIP_DEBUG # define PIP_DEBUG
//! Macro is defined when host is any Windows //! \brief
//! \~english Macro is defined when host is any Windows
//! \~russian Макрос объявлен когда система Windows
# define WINDOWS # define WINDOWS
//! Macro is defined when host is QNX or Blackberry //! \brief
//! \~english Macro is defined when host is QNX or Blackberry
//! \~russian Макрос объявлен когда система QNX или Blackberry
# define QNX # define QNX
//! Macro is defined when host is Blackberry //! \brief
//! \~english Macro is defined when host is Blackberry
//! \~russian Макрос объявлен когда система Blackberry
# define BLACKBERRY # define BLACKBERRY
//! Macro is defined when host is FreeBSD //! \brief
//! \~english Macro is defined when host is FreeBSD
//! \~russian Макрос объявлен когда система FreeBSD
# define FREE_BSD # define FREE_BSD
//! Macro is defined when host is Mac OS //! \brief
//! \~english Macro is defined when host is Mac OS
//! \~russian Макрос объявлен когда система Mac OS
# define MAC_OS # define MAC_OS
//! Macro is defined when host is Android //! \brief
//! \~english Macro is defined when host is Android
//! \~russian Макрос объявлен когда система Android
# define ANDROID # define ANDROID
//! Macro is defined when host is any Linux //! \brief
//! \~english Macro is defined when host is any Linux
//! \~russian Макрос объявлен когда система Linux
# define LINUX # define LINUX
//! Macro is defined when compiler is GCC or MinGW //! \brief
//! \~english Macro is defined when compiler is GCC or MinGW
//! \~russian Макрос объявлен когда компилятор GCC или MinGW
# define CC_GCC # define CC_GCC
//! Macro is defined when PIP is decided that host is support language //! \brief
//! \~english Macro is defined when PIP is decided that host is support language
//! \~russian Макрос объявлен когда PIP решил что система поддерживает локализацию
# define HAS_LOCALE # define HAS_LOCALE
//! Macro is defined when compiler is Visual Studio //! \brief
//! \~english Macro is defined when compiler is Visual Studio
//! \~russian Макрос объявлен когда компилятор Visual Studio
# define CC_VC # define CC_VC
//! Macro is defined when compiler is unknown //! \brief
//! \~english Macro is defined when compiler is unknown
//! \~russian Макрос объявлен когда компилятор неизвестен
# define CC_OTHER # define CC_OTHER
//! Macro is defined when PIP can use "rt" library for "PITimer::ThreadRT" timers implementation //! \brief
//! \~english Macro is defined when PIP can use "rt" library for "PITimer::ThreadRT" timers implementation
//! \~russian Макрос объявлен когда PIP может использовать библиотеку "rt" для "PITimer::ThreadRT" реализации таймера
# define PIP_TIMER_RT # define PIP_TIMER_RT
//! Macro to declare private section, export is optional //! \brief
//! \~english Macro to declare private section, "export" is optional
//! \~russian Макрос для объявления частной секции, "export" необязателен
# define PRIVATE_DECLARATION(export) # define PRIVATE_DECLARATION(export)
//! Macro to start definition of private section //! \brief
//! \~english Macro to start definition of private section
//! \~russian Макрос для начала реализации частной секции
# define PRIVATE_DEFINITION_START(Class) # define PRIVATE_DEFINITION_START(Class)
//! Macro to end definition of private section //! \brief
//! \~english Macro to end definition of private section
//! \~russian Макрос для окончания реализации частной секции
# define PRIVATE_DEFINITION_END(Class) # define PRIVATE_DEFINITION_END(Class)
//! Macro to access private section by pointer //! \brief
//! \~english Macro to access private section by pointer
//! \~russian Макрос для доступа к частной секции
# define PRIVATE # define PRIVATE
//! Macro to access private section by pointer without brakes () //! \brief
//! \~english Macro to access private section by pointer without brakes ()
//! \~russian Макрос для доступа к частной секции без обрамляющих скобок ()
# define PRIVATEWB # define PRIVATEWB
//! Macro to start static initializer //! \brief
//! \~english Macro to start static initializer
//! \~russian Макрос для начала статической инициализации
# define STATIC_INITIALIZER_BEGIN # define STATIC_INITIALIZER_BEGIN
//! Macro to end static initializer //! \brief
//! \~english Macro to end static initializer
//! \~russian Макрос для окончания статической инициализации
# define STATIC_INITIALIZER_END # define STATIC_INITIALIZER_END
@@ -139,6 +203,8 @@
extern long long __pi_perf_freq; extern long long __pi_perf_freq;
#endif #endif
#ifndef DOXYGEN
#ifdef ANDROID #ifdef ANDROID
///# define tcdrain(fd) ioctl(fd, TCSBRK, 1) ///# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
//inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;} //inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
@@ -221,7 +287,7 @@
# define DEPRECATED # define DEPRECATED
#endif #endif
#endif //DOXYGEN
// Private data macros // Private data macros
#ifndef DOXYGEN #ifndef DOXYGEN
@@ -281,21 +347,32 @@
#endif #endif
//! Macro used for infinite loop //! \brief
//! \~english Macro used for infinite loop
//! \~russian Макрос для бесконечного цикла
#define FOREVER for (;;) #define FOREVER for (;;)
//! Macro used for infinite wait //! \brief
#define FOREVER_WAIT FOREVER msleep(PIP_MIN_MSLEEP); //! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define FOREVER_WAIT FOREVER piMinSleep;
//! Macro used for infinite wait //! \brief
#define WAIT_FOREVER FOREVER msleep(PIP_MIN_MSLEEP); //! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define WAIT_FOREVER FOREVER piMinSleep;
//! global variable enabling output to piCout, default is true //! \brief
//! \~english Global variable enabling output to piCout, default is true
//! \~russian Глобальная переменная, включающая вывод в piCout, при старте true
extern PIP_EXPORT bool piDebug; extern PIP_EXPORT bool piDebug;
//! global variable that set minimum real update interval //! \brief
//! \~english Global variable that set minimum real update interval
//! for function PIInit::mountInfo(), default is 10000 ms //! for function PIInit::mountInfo(), default is 10000 ms
//! \~russian Глобальная переменная минимального ожидания между реальным обновлением
//! в методе PIInit::mountInfo(), по умолчанию 10000 мс
extern PIP_EXPORT double piMountInfoRefreshIntervalMs; extern PIP_EXPORT double piMountInfoRefreshIntervalMs;
typedef unsigned char uchar; typedef unsigned char uchar;
@@ -306,12 +383,20 @@ typedef unsigned long long ullong;
typedef long long llong; typedef long long llong;
typedef long double ldouble; typedef long double ldouble;
/*! @brief Templated function for swap two values //! \brief
* \details Example:\n \snippet piincludes.cpp swap */ //! \~english Templated function for swap two values
//! \~russian Шаблонный метод для перестановки двух значений
//! \details
//! \~english Example:\n \snippet piincludes.cpp swap
//! \~russian Пример:\n \snippet piincludes.cpp swap
template<typename T> inline void piSwap(T & f, T & s) {T t(std::move(f)); f = std::move(s); s = std::move(t);} template<typename T> inline void piSwap(T & f, T & s) {T t(std::move(f)); f = std::move(s); s = std::move(t);}
/*! @brief Templated function for swap two values without "=" //! \brief
* \details Example:\n \snippet piincludes.cpp swapBinary */ //! \~english Templated function for swap two values without "="
//! \~russian Шаблонный метод для перестановки двух значений без использования "="
//! \details
//! \~english Example:\n \snippet piincludes.cpp swapBinary
//! \~russian Пример:\n \snippet piincludes.cpp swapBinary
template<typename T> inline void piSwapBinary(T & f, T & s) { template<typename T> inline void piSwapBinary(T & f, T & s) {
if ((size_t*)&f == (size_t*)&s) return; if ((size_t*)&f == (size_t*)&s) return;
size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T); size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
@@ -346,8 +431,12 @@ template<> inline void piSwapBinary(const void *& f, const void *& s) {
} }
/*! @brief Function for compare two values without "=" by raw content //! \brief
* \details Example:\n \snippet piincludes.cpp compareBinary */ //! \~english Function for compare two values without "==" by raw content
//! \~russian Метод для сравнения двух значений без использования "==" (по сырому содержимому)
//! \details
//! \~english Example:\n \snippet piincludes.cpp compareBinary
//! \~russian Пример:\n \snippet piincludes.cpp compareBinary
inline bool piCompareBinary(const void * f, const void * s, size_t size) { inline bool piCompareBinary(const void * f, const void * s, size_t size) {
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
if (((const uchar*)f)[i] != ((const uchar*)s)[i]) if (((const uchar*)f)[i] != ((const uchar*)s)[i])
@@ -355,135 +444,304 @@ inline bool piCompareBinary(const void * f, const void * s, size_t size) {
return true; return true;
} }
/*! @brief Templated function return round of float falue //! \brief
* \details Round is the nearest integer value \n //! \~english Templated function return round of float falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий округленное значение
* - \c piRoundf for "float" //! \details
* - \c piRoundd for "double" //! \~english
* //! Round is the nearest integer value \n
* Example: //! There are some macros:
* \snippet piincludes.cpp round */ //! - \c piRoundf for "float"
//! - \c piRoundd for "double"
//!
//! Example:
//! \snippet piincludes.cpp round
//! \~russian
//! Округленное значение - это ближайшее целое число\n
//! Есть несколько макросов:
//! - \c piRoundf для "float"
//! - \c piRoundd для "double"
//!
//! Пример:
//! \snippet piincludes.cpp round
template<typename T> inline constexpr int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));} template<typename T> inline constexpr int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));}
/*! @brief Templated function return floor of float falue //! \brief
* \details Floor is the largest integer that is not greater than value \n //! \~english Templated function return floor of float falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий floor значение
* - \c piFloorf for "float" //! \details
* - \c piFloord for "double" //! \~english
* //! Floor is the largest integer that is not greater than "v" \n
* Example: //! There are some macros:
* \snippet piincludes.cpp floor */ //! - \c piFloorf for "float"
//! - \c piFloord for "double"
//!
//! Example:
//! \snippet piincludes.cpp floor
//! \~russian
//! Floor значение - это наибольшее целое, не большее чем "v"\n
//! Есть несколько макросов:
//! - \c piFloorf для "float"
//! - \c piFloord для "double"
//!
//! Пример:
//! \snippet piincludes.cpp floor
template<typename T> inline constexpr int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);} template<typename T> inline constexpr int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);}
/*! @brief Templated function return ceil of float falue //! \brief
* \details Ceil is the smallest integer that is not less than value \n //! \~english Templated function return ceil of float falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий ceil значение
* - \c piCeilf for "float" //! \details
* - \c piCeild for "double" //! \~english
* //! Ceil is the smallest integer that is not less than "v" \n
* Example: //! There are some macros:
* \snippet piincludes.cpp ceil */ //! - \c piCeilf for "float"
//! - \c piCeild for "double"
//!
//! Example:
//! \snippet piincludes.cpp ceil
//! \~russian
//! Ceil значение - это наименьшее целое, не меньшее чем "v" \n
//! Есть несколько макросов:
//! - \c piCeilf для "float"
//! - \c piCeild для "double"
//!
//! Пример:
//! \snippet piincludes.cpp ceil
template<typename T> inline constexpr int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;} template<typename T> inline constexpr int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;}
/*! @brief Templated function return absolute of numeric falue //! \brief
* \details Absolute is the positive or equal 0 value \n //! \~english Templated function return absolute of numeric falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий модуль числового значения
* - \c piAbss for "short" //! \details
* - \c piAbsi for "int" //! \~english
* - \c piAbsl for "long" //! Absolute is the positive or equal 0 value \n
* - \c piAbsll for "llong" //! There are some macros:
* - \c piAbsf for "float" //! - \c piAbss for "short"
* - \c piAbsd for "double" //! - \c piAbsi for "int"
* //! - \c piAbsl for "long"
* Example: //! - \c piAbsll for "llong"
* \snippet piincludes.cpp abs */ //! - \c piAbsf for "float"
//! - \c piAbsd for "double"
//!
//! Example:
//! \snippet piincludes.cpp abs
//! \~russian
//! Модуль числового значения всегда >= 0 \n
//! Есть несколько макросов:
//! - \c piAbss для "short"
//! - \c piAbsi для "int"
//! - \c piAbsl для "long"
//! - \c piAbsll для "llong"
//! - \c piAbsf для "float"
//! - \c piAbsd для "double"
//!
//! Пример:
//! \snippet piincludes.cpp abs
template<typename T> inline constexpr T piAbs(const T & v) {return (v >= T(0) ? v : -v);} template<typename T> inline constexpr T piAbs(const T & v) {return (v >= T(0) ? v : -v);}
/*! @brief Templated function return minimum of two values //! \brief
* \details There are some macros: //! \~english Templated function return minimum of two values
* - \c piMins for "short" //! \~russian Шаблонный метод, возвращающий минимум из двух значений
* - \c piMini for "int" //! \details
* - \c piMinl for "long" //! \~english
* - \c piMinll for "llong" //! There are some macros:
* - \c piMinf for "float" //! - \c piMins for "short"
* - \c piMind for "double" //! - \c piMini for "int"
* //! - \c piMinl for "long"
* Example: //! - \c piMinll for "llong"
* \snippet piincludes.cpp min2 */ //! - \c piMinf for "float"
//! - \c piMind for "double"
//!
//! Example:
//! \snippet piincludes.cpp min2
//! \~russian
//! Есть несколько макросов:
//! - \c piMins для "short"
//! - \c piMini для "int"
//! - \c piMinl для "long"
//! - \c piMinll для "llong"
//! - \c piMinf для "float"
//! - \c piMind для "double"
//!
//! Пример:
//! \snippet piincludes.cpp min2
template<typename T> inline constexpr T piMin(const T & f, const T & s) {return ((f > s) ? s : f);} template<typename T> inline constexpr T piMin(const T & f, const T & s) {return ((f > s) ? s : f);}
/*! @brief Templated function return minimum of tree values //! \brief
* \details There are some macros: //! \~english Templated function return minimum of tree values
* - \c piMins for "short" //! \~russian Шаблонный метод, возвращающий минимум из трех значений
* - \c piMini for "int" //! \details
* - \c piMinl for "long" //! \~english
* - \c piMinll for "llong" //! There are some macros:
* - \c piMinf for "float" //! - \c piMins for "short"
* - \c piMind for "double" //! - \c piMini for "int"
* //! - \c piMinl for "long"
* Example: //! - \c piMinll for "llong"
* \snippet piincludes.cpp min3 */ //! - \c piMinf for "float"
//! - \c piMind for "double"
//!
//! Example:
//! \snippet piincludes.cpp min3
//! \~russian
//! Есть несколько макросов:
//! - \c piMins для "short"
//! - \c piMini для "int"
//! - \c piMinl для "long"
//! - \c piMinll для "llong"
//! - \c piMinf для "float"
//! - \c piMind для "double"
//!
//! Пример:
//! \snippet piincludes.cpp min3
template<typename T> inline constexpr T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));} template<typename T> inline constexpr T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));}
/*! @brief Templated function return maximum of two values //! \brief
* \details There are some macros: //! \~english Templated function return maximum of two values
* - \c piMaxs for "short" //! \~russian Шаблонный метод, возвращающий максимум из двух значений
* - \c piMaxi for "int" //! \details
* - \c piMaxl for "long" //! \~english
* - \c piMaxll for "llong" //! There are some macros:
* - \c piMaxf for "float" //! - \c piMaxs for "short"
* - \c piMaxd for "double" //! - \c piMaxi for "int"
* //! - \c piMaxl for "long"
* Example: //! - \c piMaxll for "llong"
* \snippet piincludes.cpp max2 */ //! - \c piMaxf for "float"
//! - \c piMaxd for "double"
//!
//! Example:
//! \snippet piincludes.cpp max2
//! \~russian
//! Есть несколько макросов:
//! - \c piMaxs для "short"
//! - \c piMaxi для "int"
//! - \c piMaxl для "long"
//! - \c piMaxll для "llong"
//! - \c piMaxf для "float"
//! - \c piMaxd для "double"
//!
//! Пример:
//! \snippet piincludes.cpp max2
template<typename T> inline constexpr T piMax(const T & f, const T & s) {return ((f < s) ? s : f);} template<typename T> inline constexpr T piMax(const T & f, const T & s) {return ((f < s) ? s : f);}
/*! @brief Templated function return maximum of tree values //! \brief
* \details There are some macros: //! \~english Templated function return maximum of tree values
* - \c piMaxs for "short" //! \~russian Шаблонный метод, возвращающий максимум из трех значений
* - \c piMaxi for "int" //! \details
* - \c piMaxl for "long" //! \~english
* - \c piMaxll for "llong" //! There are some macros:
* - \c piMaxf for "float" //! - \c piMaxs for "short"
* - \c piMaxd for "double" //! - \c piMaxi for "int"
* //! - \c piMaxl for "long"
* Example: //! - \c piMaxll for "llong"
* \snippet piincludes.cpp max3 */ //! - \c piMaxf for "float"
//! - \c piMaxd for "double"
//!
//! Example:
//! \snippet piincludes.cpp max3
//! \~russian
//! Есть несколько макросов:
//! - \c piMaxs для "short"
//! - \c piMaxi для "int"
//! - \c piMaxl для "long"
//! - \c piMaxll для "llong"
//! - \c piMaxf для "float"
//! - \c piMaxd для "double"
//!
//! Пример:
//! \snippet piincludes.cpp max3
template<typename T> inline constexpr T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));} template<typename T> inline constexpr T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));}
/*! @brief Templated function return clamped value //! \brief
* \details Clamped is the not greater than "max" and not lesser than "min" value \n //! \~english Templated function return clamped value
* There are some macros: //! \~russian Шаблонный метод, возвращающий ограниченное значение
* - \c piClamps for "short" //! \details
* - \c piClampi for "int" //! \~english
* - \c piClampl for "long" //! Clamped is the not greater than "max" and not lesser than "min" value \n
* - \c piClampll for "llong" //! There are some macros:
* - \c piClampf for "float" //! - \c piClamps for "short"
* - \c piClampd for "double" //! - \c piClampi for "int"
* //! - \c piClampl for "long"
* Example: //! - \c piClampll for "llong"
* \snippet piincludes.cpp clamp */ //! - \c piClampf for "float"
//! - \c piClampd for "double"
//!
//! Example:
//! \snippet piincludes.cpp clamp
//! \~russian
//! Ограниченное значение - не больше чем "max" и не меньше чем "min"
//! Есть несколько макросов:
//! - \c piClamps для "short"
//! - \c piClampi для "int"
//! - \c piClampl для "long"
//! - \c piClampll для "llong"
//! - \c piClampf для "float"
//! - \c piClampd для "double"
//!
//! Пример:
//! \snippet piincludes.cpp clamp
template<typename T> inline constexpr T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));} template<typename T> inline constexpr T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));}
/// Function inverse byte order in memory block //! \brief
//! \~english Function inverse byte order in memory block ([1..N] -> [N..1])
//! \~russian Метод для смены порядка байт в блоке памяти ([1..N] -> [N..1])
inline void piLetobe(void * data, int size) { inline void piLetobe(void * data, int size) {
for (int i = 0; i < size / 2; i++) for (int i = 0; i < size / 2; i++)
piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[i]); piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[i]);
} }
/// @brief Templated function that inverse byte order of value "v" //! \brief
//! \~english Function for compare two numeric values with epsilon
//! \~russian Метод для сравнения двух чисел с порогом
//! \details
//! \~english
//! There are some macros:
//! - \c piComparef for "float"
//! - \c piCompared for "double"
//!
//! Example:
//! \snippet piincludes.cpp compare
//! \~russian
//! Есть несколько макросов:
//! - \c piComparef для "float"
//! - \c piCompared для "double"
//!
//! Пример:
//! \snippet piincludes.cpp compare
template<typename T>
inline bool piCompare(const T & a, const T & b, const T & epsilon = std::numeric_limits<T>::epsilon()) {
return piAbs(a - b) <= epsilon;
}
//! \brief
//! \~english Templated function that inverse byte order of value "v"
//! \~russian Шаблонный метод, меняющий порядок байт в переменной "v"
template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));} template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));}
/*! @brief Templated function that returns "v" with inversed byte order //! \brief
* \details This function used to convert values between little and big endian \n //! \~english Templated function that returns "v" with inversed byte order
* There are some macros: //! \~russian Шаблонный метод, возвращающий переменную "v" с измененным порядком байт
* - \c piLetobes for "ushort" //! \details
* - \c piLetobei for "uint" //! \~english
* - \c piLetobel for "ulong" //! This function used to convert values between little and big endian \n
* - \c piLetobell for "ullong" //! There are some macros:
* //! - \c piLetobes for "ushort"
* Example: //! - \c piLetobei for "uint"
* \snippet piincludes.cpp letobe */ //! - \c piLetobel for "ulong"
//! - \c piLetobell for "ullong"
//!
//! Example:
//! \snippet piincludes.cpp letobe
//! \~russian
//! Этот метод используется для изменения порядка байт между little и big endian
//! Есть несколько макросов:
//! - \c piLetobes для "ushort"
//! - \c piLetobei для "uint"
//! - \c piLetobel для "ulong"
//! - \c piLetobell для "ullong"
//!
//! Пример:
//! \snippet piincludes.cpp letobe
template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;} template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
// specialization // specialization
@@ -500,7 +758,9 @@ template<> inline float piLetobe(const float & v) {
return a.f; return a.f;
} }
/// @brief Generic hash function, implements murmur3/32 algorithm //! \brief
//! \~english Generic hash function, implements murmur3/32 algorithm
//! \~russian Хэш-функция общего назначения, по алгоритму murmur3/32
inline uint piHashData(const uchar * data, uint len, uint seed = 0) { inline uint piHashData(const uchar * data, uint len, uint seed = 0) {
if (!data || len <= 0) return 0u; if (!data || len <= 0) return 0u;
uint h = seed; uint h = seed;
@@ -558,6 +818,8 @@ template<> inline uint piHash(const ldouble & v) {return piHashData((const uchar
#define piRoundf piRound<float> #define piRoundf piRound<float>
#define piRoundd piRound<double> #define piRoundd piRound<double>
#define piComparef piCompare<float>
#define piCompared piCompare<double>
#define piFloorf piFloor<float> #define piFloorf piFloor<float>
#define piFloord piFloor<double> #define piFloord piFloor<double>
#define piCeilf piCeil<float> #define piCeilf piCeil<float>

View File

@@ -221,22 +221,22 @@ PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
} }
uchar PIByteArray::checksumPlain8() const { uchar PIByteArray::checksumPlain8(bool inverse) const {
uchar c = 0; uchar c = 0;
int sz = size_s(); int sz = size_s();
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i)
c += at(i); c += at(i);
c = ~(c + 1); if (inverse) c = ~(c + 1);
return c; return c;
} }
uint PIByteArray::checksumPlain32() const { uint PIByteArray::checksumPlain32(bool inverse) const {
uint c = 0; uint c = 0;
int sz = size_s(); int sz = size_s();
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i)
c += at(i) * (i + 1); c += at(i) * (i + 1);
c = ~(c + 1); if (inverse) c = ~(c + 1);
return c; return c;
} }

View File

@@ -27,6 +27,7 @@
#include "pibitarray.h" #include "pibitarray.h"
#include "pimap.h" #include "pimap.h"
#include "pivector2d.h" #include "pivector2d.h"
#include <stdio.h>
#ifdef FREERTOS #ifdef FREERTOS
# define _TYPENAME_(T) "?" # define _TYPENAME_(T) "?"
@@ -85,6 +86,8 @@ public:
PIByteArray(const PIByteArray & o): PIDeque<uchar>(o) {} PIByteArray(const PIByteArray & o): PIDeque<uchar>(o) {}
PIByteArray(const PIDeque<uchar> & o): PIDeque<uchar>(o) {}
PIByteArray(PIByteArray && o): PIDeque<uchar>(std::move(o)) {} PIByteArray(PIByteArray && o): PIDeque<uchar>(std::move(o)) {}
//! Constructs 0-filled byte array with size "size" //! Constructs 0-filled byte array with size "size"
@@ -116,6 +119,12 @@ public:
//! Return resized byte array //! Return resized byte array
PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;} PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;}
//! Return sub-array starts from "index" and has "count" or less bytes
PIByteArray getRange(size_t index, size_t count) const {
return PIDeque<uchar>::getRange(index, count);
}
//! Convert data to Base 64 and return this byte array //! Convert data to Base 64 and return this byte array
PIByteArray & convertToBase64(); PIByteArray & convertToBase64();
@@ -146,18 +155,18 @@ public:
PIByteArray & append(uchar t) {push_back(t); return *this;} PIByteArray & append(uchar t) {push_back(t); return *this;}
//! Returns 8-bit checksum //! Returns 8-bit checksum
//! sum all bytes, add 1, inverse //! sum all bytes, if inverse - add 1, inverse
//! Pseudocode: //! Pseudocode:
//! sum += at(i); //! sum += at(i);
//! return ~(sum + 1) //! return ~(sum + 1)
uchar checksumPlain8() const; uchar checksumPlain8(bool inverse = true) const;
//! Returns 32-bit checksum //! Returns 32-bit checksum
//! sum all bytes multiplyed by index+1, add 1, inverse //! sum all bytes multiplyed by index+1, if inverse - add 1, inverse
//! Pseudocode: //! Pseudocode:
//! sum += at(i) * (i + 1); //! sum += at(i) * (i + 1);
//! return ~(sum + 1) //! return ~(sum + 1)
uint checksumPlain32() const; uint checksumPlain32(bool inverse = true) const;
//! Returns hash //! Returns hash
uint hash() const; uint hash() const;
@@ -190,34 +199,39 @@ public:
//! \relatesalso PIByteArray @brief Byte arrays compare operator //! \relatesalso PIByteArray @brief Byte arrays compare operator
inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) { inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) { if (v0.size() == v1.size()) {
for (uint i = 0; i < v0.size(); ++i) if (v0.isEmpty()) return false;
if (v0[i] != v1[i]) return memcmp(v0.data(), v1.data(), v0.size()) < 0;
return v0[i] < v1[i];
return false;
} }
return v0.size() < v1.size(); return v0.size() < v1.size();
} }
//! \relatesalso PIByteArray @brief Byte arrays compare operator //! \relatesalso PIByteArray @brief Byte arrays compare operator
inline bool operator ==(PIByteArray & f, PIByteArray & s) { inline bool operator >(const PIByteArray & v0, const PIByteArray & v1) {
if (f.size_s() != s.size_s()) if (v0.size() == v1.size()) {
return false; if (v0.isEmpty()) return false;
for (int i = 0; i < f.size_s(); ++i) return memcmp(v0.data(), v1.data(), v0.size()) > 0;
if (f[i] != s[i]) }
return false; return v0.size() > v1.size();
return true;
} }
//! \relatesalso PIByteArray @brief Byte arrays compare operator //! \relatesalso PIByteArray @brief Byte arrays compare operator
inline bool operator !=(PIByteArray & f, PIByteArray & s) { inline bool operator ==(const PIByteArray & v0, const PIByteArray & v1) {
if (f.size_s() != s.size_s()) if (v0.size() == v1.size()) {
return true; if (v0.isEmpty()) return true;
for (int i = 0; i < f.size_s(); ++i) return memcmp(v0.data(), v1.data(), v0.size()) == 0;
if (f[i] != s[i]) }
return true;
return false; return false;
} }
//! \relatesalso PIByteArray @brief Byte arrays compare operator
inline bool operator !=(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return false;
return memcmp(v0.data(), v1.data(), v0.size()) != 0;
}
return true;
}
#ifdef PIP_STD_IOSTREAM #ifdef PIP_STD_IOSTREAM
//! \relatesalso PIByteArray @brief Output to std::ostream operator //! \relatesalso PIByteArray @brief Output to std::ostream operator
inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba); inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);

View File

@@ -24,6 +24,7 @@
#include "pistring_std.h" #include "pistring_std.h"
#ifdef WINDOWS #ifdef WINDOWS
# include <windows.h> # include <windows.h>
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
#endif #endif

View File

@@ -95,7 +95,10 @@ int randomi() {
} }
/*! \mainpage What is PIP /*! \~english \mainpage What is PIP
* \~russian \mainpage Что такое PIP
*
* \~english
* PIP - Platform-Independent Primitives - is crossplatform library for C++ developers. * PIP - Platform-Independent Primitives - is crossplatform library for C++ developers.
* It is wrap around STL and pure C++. This library can help developers write non-GUI * It is wrap around STL and pure C++. This library can help developers write non-GUI
* projects much more quickly, efficiently and customizable than on pure C++. * projects much more quickly, efficiently and customizable than on pure C++.
@@ -112,10 +115,16 @@ int randomi() {
* * executor (\a PIThreadPoolExecutor) * * executor (\a PIThreadPoolExecutor)
* * blocking dequeue (\a PIBlockingDequeue) * * blocking dequeue (\a PIBlockingDequeue)
* * timer (\a PITimer) * * timer (\a PITimer)
* * console (information output) (\a PIConsole) * * tiling console (with widgets) (\a PIScreen)
* * stand-alone * * simple text rows
* * server * * scroll bar
* * client * * list
* * button
* * buttons group
* * check box
* * progress bar
* * PICout output
* * text input
* * I/O devices * * I/O devices
* * base class (\a PIIODevice) * * base class (\a PIIODevice)
* * file (\a PIFile) * * file (\a PIFile)
@@ -134,15 +143,72 @@ int randomi() {
* * peering net node (\a PIPeer) * * peering net node (\a PIPeer)
* * process (\a PIProcess) * * process (\a PIProcess)
* * state machine (\a PIStateMachine) * * state machine (\a PIStateMachine)
* \n \n Basic using of PIP described at page \ref using_basic */ * \n \n Basic using of PIP described at page \ref using_basic
*
* \~russian
* PIP - Platform-Independent Primitives - кроссплатформенная библиотека для разработчиков на C++.
* It is wrap around STL and pure C++. This library can help developers write non-GUI
* projects much more quickly, efficiently and customizable than on pure C++.
* PIP предоставляет следующие классы:
* * общение с консолью (\a PICout)
* * контейнеры (\a PIVector, \a PIList, \a PIMap, \a PIStack)
* * байтовый массив (\a PIByteArray)
* * строка (\a PIString, \a PIStringList)
* * базовый объект (события и обработчики) (\a PIObject)
* * многопоточность
* * поток (\a PIThread)
* * исполнитель (\a PIThreadPoolExecutor)
* * блокирующая очередь (\a PIBlockingDequeue)
* * таймер (\a PITimer)
* * тайлинговая консоль (с виджетами) (\a PIScreen)
* * простой вывод строк
* * скроллбар
* * лист
* * кнопка
* * группа кнопок
* * галочка
* * прогрессбар
* * вывод PICout
* * текстовый ввод
* * устройства ввода/вывода
* * базовый класс (\a PIIODevice)
* * файл (\a PIFile)
* * последовательный порт (\a PISerial)
* * ethernet (\a PIEthernet)
* * USB (\a PIUSB)
* * packets extractor (\a PIPacketExtractor)
* * бинарный логфайл (\a PIBinaryLog)
* * сложное составное устройство (\a PIConnection)
* * поддержка библиотек времени выполнения
* * базовая функциональность (\a PILibrary)
* * плагин (\a PIPluginLoader)
* * диагностика качества связи (\a PIDiagnostics)
* * парсер аргументов командной строки (\a PICLI)
* * вычислитель (\a PIEvaluator)
* * пиринговая сеть (\a PIPeer)
* * процесс (\a PIProcess)
* * машина состояний (\a PIStateMachine)
* \n \n Базовое использование PIP описано на странице \ref using_basic
*/
/*! \page using_basic Getting started /*! \~english \page using_basic Getting started
* \~russian \page using_basic Простые начала
*
* \~english
* Many novice programmers are solved many common task with system integrity: output to console, * Many novice programmers are solved many common task with system integrity: output to console,
* keyboard buttons press detecting, working with serial ports, ethernet or files, and many other. * keyboard buttons press detecting, working with serial ports, ethernet or files, and many other.
* These tasks can solve this library, and code, based only on PIP will be compile and work * These tasks can solve this library, and code, based only on PIP will be compile and work
* similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX. * similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX.
* Typical application on PIP looks like this: \n * Typical application on PIP looks like this: \n
*
* \~russian
* Многие начинающие программисты решают общие задачи взаимодействия с операционной системой:
* вывод в консоль, определение нажатия клавиш, работа с последовательными портами, сетью или файлами,
* и многое другое. Эти задачи решены в библиотеке, и код, основанный на PIP будет компилироваться
* и работать одинаково на многих системах: Windows, любой Linux, Red Hat, FreeBSD, MacOS X и QNX.
* Типовое приложение на PIP выглядит примерно так: \n
*
\code{.cpp} \code{.cpp}
#include <pip.h> #include <pip.h>
@@ -232,15 +298,32 @@ int main(int argc, char * argv[]) {
return 0; return 0;
}; };
\endcode \endcode
*
* \~english
* This code demonstrates simple interactive configurable program, which can be started with console * This code demonstrates simple interactive configurable program, which can be started with console
* display or not, and with debug or not. \b MainClass is central class that also can be inherited from * display or not, and with debug or not. \b MainClass is central class that also can be inherited from
* \a PIThread and reimplement \a run() function. * \a PIThread and reimplement \a run() function.
* \n Many PIP classes has events and event handlers, which can be connected one to another. * \n Many PIP classes has events and event handlers, which can be connected one to another.
* Details you can see at \a PIObject reference page (\ref PIObject_sec0). * Details you can see at \a PIObject reference page (\ref PIObject_sec0).
* \n To configure your program from file use \a PIConfig. * \n To configure your program from file use \a PIConfig.
* \n If you want more information see \ref using_advanced */ * \n If you want more information see \ref using_advanced
*
* \~russian
* Этот код демонстрирует простую конфигурируемую программу, которая может быть запущена с
* This code demonstrates simple interactive configurable program, which can be started with console
* display or not, and with debug or not. \b MainClass is central class that also can be inherited from
* \a PIThread and reimplement \a run() function.
* \n Many PIP classes has events and event handlers, which can be connected one to another.
* Details you can see at \a PIObject reference page (\ref PIObject_sec0).
* \n To configure your program from file use \a PIConfig.
*/
/*! \page using_advanced Advanced using /*! \page using_advanced Advanced using
* Sorry, creativity crysis xD * Sorry, creativity crysis xD
*/ */
/*
* \~english
* \~russian
*/

View File

@@ -42,10 +42,18 @@ struct lconv;
extern PIP_EXPORT lconv * currentLocale; extern PIP_EXPORT lconv * currentLocale;
/*! \fn errorString() //! \brief
* @brief Return readable error description in format "code <number> - <description>" */ //! \~english
//! Return readable error description in format "code <number> - <description>"
//! \~russian
//! Возвращает читаемое описание ошибки в формате "code <номер> - <описание>"
PIP_EXPORT PIString errorString(); PIP_EXPORT PIString errorString();
//! \brief
//! \~english
//! Reset last error
//! \~russian
//! Сброс последней ошибки
PIP_EXPORT void errorClear(); PIP_EXPORT void errorClear();
PIP_EXPORT void piqsort(void* base, size_t num, size_t size, int (*compar)(const void*,const void*)); PIP_EXPORT void piqsort(void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
@@ -53,7 +61,9 @@ PIP_EXPORT void piqsort(void* base, size_t num, size_t size, int (*compar)(const
PIP_EXPORT void randomize(); PIP_EXPORT void randomize();
PIP_EXPORT int randomi(); PIP_EXPORT int randomi();
/// Return readable version of PIP //! \brief
//! \~english Return readable version of PIP
//! \~russian Возвращает читаемую версию PIP
PIP_EXPORT PIString PIPVersion(); PIP_EXPORT PIString PIPVersion();
#endif // PIINCLUDES_H #endif // PIINCLUDES_H

View File

@@ -91,9 +91,11 @@ PIObject::~PIObject() {
mutexObjects().lock(); mutexObjects().lock();
objects().removeAll(this); objects().removeAll(this);
mutexObjects().unlock(); mutexObjects().unlock();
piDisconnect(this); deleted(this);
piDisconnectAll();
} }
PIMap<PIString, PIVariant> PIObject::properties() const { PIMap<PIString, PIVariant> PIObject::properties() const {
PIMap<PIString, PIVariant> ret; PIMap<PIString, PIVariant> ret;
piForeachC (PropertyHash p, properties_) piForeachC (PropertyHash p, properties_)
@@ -141,50 +143,6 @@ bool PIObject::executeQueued(PIObject * performer, const PIString & method, cons
} }
void PIObject::piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h) {
PIObject * o = findByName(src);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
PIMutexLocker _ml(o->mutex_connect);
PIMutexLocker _mld(((PIObject*)dest)->mutex_connect, ((PIObject*)dest) != o);
o->connections << __Connection(ev_h, 0, sig, (PIObject*)dest, dest);
((PIObject*)dest)->connectors << o;
}
void PIObject::piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * o = findByName(dest);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(o->mutex_connect, src != o);
src->connections << __Connection(ev_h, 0, sig, o, o);
((PIObject*)o)->connectors << src;
}
void PIObject::piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * s = findByName(src);
if (s == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
PIObject * d = findByName(dest);
if (d == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
PIMutexLocker _ml(s->mutex_connect);
PIMutexLocker _mld(d->mutex_connect, s != d);
s->connections << __Connection(ev_h, 0, sig, d, d);
d->connectors << s;
}
PIStringList PIObject::scopeList() const { PIStringList PIObject::scopeList() const {
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
return __meta_data()[classNameID()].scope_list; return __meta_data()[classNameID()].scope_list;
@@ -256,31 +214,33 @@ PIObject::__MetaFunc PIObject::methodEH(const void * addr) const {
} }
void PIObject::piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc) { PIObject::Connection PIObject::piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc) {
//piCout << "piConnect ..."; //piCout << "piConnect ...";
//piCout << "piConnect" << src << (void*)(dest) << sig; //piCout << "piConnect" << src << (void*)(dest) << sig;
//piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className(); //piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className();
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest_o->mutex_connect, src != dest_o); PIMutexLocker _mld(dest_o->mutex_connect, src != dest_o);
src->connections << __Connection(ev_h, e_h, sig, dest_o, dest, args); Connection conn(ev_h, e_h, sig, src, dest_o, dest, args);
src->connections << conn;
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s() << "..."; //piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s() << "...";
//piCout << "addConnector" << dest_o << src; //piCout << "addConnector" << dest_o << src;
dest_o->connectors << src; dest_o->connectors << src;
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s(); //piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s();
//piCout << "piConnect ok"; //piCout << "piConnect ok";
return conn;
} }
bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer) { PIObject::Connection PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer) {
if (src == 0 || dest_o == 0 || dest == 0) return false; if (src == 0 || dest_o == 0 || dest == 0) return Connection();
if (!src->isPIObject()) { if (!src->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")"; piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")";
return false; return Connection();
} }
if (!dest_o->isPIObject()) { if (!dest_o->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")"; piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")";
return false; return Connection();
} }
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect); PIMutexLocker mls(src->mutex_connect);
@@ -288,11 +248,11 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_
PIVector<__MetaFunc> m_src = src->findEH(sig), m_dest = dest_o->findEH(hname); PIVector<__MetaFunc> m_src = src->findEH(sig), m_dest = dest_o->findEH(hname);
if (m_src.isEmpty()) { if (m_src.isEmpty()) {
piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")"; piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
return false; return Connection();
} }
if (m_dest.isEmpty()) { if (m_dest.isEmpty()) {
piCout << "[piConnectU] Error: can`t find handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")"; piCout << "[piConnectU] Error: can`t find handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
return false; return Connection();
} }
void * addr_src(0), * addr_dest(0); void * addr_src(0), * addr_dest(0);
int args(0); int args(0);
@@ -311,25 +271,26 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_
if (addr_src == 0) { if (addr_src == 0) {
piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className() piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className()
<< "\" and handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")"; << "\" and handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
return false; return Connection();
} }
src->connections << PIObject::__Connection(addr_dest, addr_src, sig, dest_o, dest, args, performer); Connection conn(addr_dest, addr_src, sig, src, dest_o, dest, args, performer);
src->connections << conn;
if (que) performer->proc_event_queue = true; if (que) performer->proc_event_queue = true;
dest_o->connectors << src; dest_o->connectors << src;
//piCout << cc << cq << _ol.size();//"connect" << src << "->" << dest_o << ", dest.connectors.size() =" << dest_o->connectors.size(); //piCout << cc << cq << _ol.size();//"connect" << src << "->" << dest_o << ", dest.connectors.size() =" << dest_o->connectors.size();
return true; return conn;
} }
bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc) { PIObject::Connection PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc) {
if (src == 0) { if (src == 0) {
delete f; delete f;
return false; return Connection();
} }
if (!src->isPIObject()) { if (!src->isPIObject()) {
piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")"; piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")";
delete f; delete f;
return false; return Connection();
} }
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect); PIMutexLocker mls(src->mutex_connect);
@@ -338,19 +299,19 @@ bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<v
if (m_src.isEmpty()) { if (m_src.isEmpty()) {
piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")"; piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f; delete f;
return false; return Connection();
} }
if (m_src.size() != 1) { if (m_src.size() != 1) {
piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")"; piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f; delete f;
return false; return Connection();
} }
PIObject::__Connection conn(0, m_src[0].addr, sig); PIObject::Connection conn(0, m_src[0].addr, sig, src);
//piCout << "found"; //piCout << "found";
conn.functor = f; conn.functor = f;
src->connections << conn; src->connections << conn;
//piCout << "finished"; //piCout << "finished";
return true; return conn;
} }
@@ -358,7 +319,7 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest); PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) { for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]); Connection & cc(src->connections[i]);
if (cc.event == sig && cc.dest_o == dest && cc.slot == ev_h) { if (cc.event == sig && cc.dest_o == dest && cc.slot == ev_h) {
src->connections[i].destroy(); src->connections[i].destroy();
src->connections.remove(i); src->connections.remove(i);
@@ -373,7 +334,7 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest); PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) { for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]); Connection & cc(src->connections[i]);
if (cc.event == sig && cc.dest_o == dest) { if (cc.event == sig && cc.dest_o == dest) {
src->connections[i].destroy(); src->connections[i].destroy();
src->connections.remove(i); src->connections.remove(i);
@@ -387,13 +348,13 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
void PIObject::piDisconnect(PIObject * src, const PIString & sig) { void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
for (int i = 0; i < src->connections.size_s(); ++i) { for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]); Connection & cc(src->connections[i]);
if (cc.event == sig) { if (cc.event == sig) {
PIObject * dest = cc.dest_o; PIObject * dest = cc.dest_o;
if (!dest) {
src->connections[i].destroy(); src->connections[i].destroy();
src->connections.remove(i); src->connections.remove(i);
i--; i--;
if (dest) {
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS) #if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
PIMutexLocker _mld(dest->mutex_connect, src != dest); PIMutexLocker _mld(dest->mutex_connect, src != dest);
#endif #endif
@@ -404,37 +365,38 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
} }
void PIObject::piDisconnect(PIObject * src) { void PIObject::piDisconnectAll() {
src->deleted(src); PIMutexLocker _ml(mutex_connect);
PIMutexLocker _ml(src->mutex_connect); PIVector<PIObject * > cv = connectors.toVector();
PIVector<PIObject * > cv = src->connectors.toVector(); // piCout << "disconnect connectors =" << connectors.size();
piForeach (PIObject * o, cv) { piForeach (PIObject * o, cv) {
//piCout << "disconnect"<< src->className()<< o->className(); // piCout << "disconnect"<< src << o;
if (!o || (o == src)) continue; if (!o || (o == this)) continue;
if (!o->isPIObject()) continue; if (!o->isPIObject()) continue;
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS) #if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
PIMutexLocker _mld(o->mutex_connect, src != o); PIMutexLocker _mld(o->mutex_connect, this != o);
#endif #endif
PIVector<__Connection> & oc(o->connections); PIVector<Connection> & oc(o->connections);
for (int i = 0; i < oc.size_s(); ++i) { for (int i = 0; i < oc.size_s(); ++i) {
if (oc[i].functor) continue; if (oc[i].functor) continue;
//piCout << " check" << (void*)(oc[i].dest_o) << "==" << (void*)(src); //piCout << " check" << (void*)(oc[i].dest_o) << "==" << (void*)(src);
if (oc[i].dest_o == src) { if (oc[i].dest_o == this) {
oc[i].destroy(); oc[i].destroy();
oc.remove(i); oc.remove(i);
--i; --i;
} }
} }
} }
piForeachC (PIObject::__Connection & c, src->connections) { // piCout << "disconnect connections =" << connections.size();
piForeachC (PIObject::Connection & c, connections) {
if (c.functor) continue; if (c.functor) continue;
if (!c.dest_o) continue; if (!c.dest_o) continue;
if (!c.dest_o->isPIObject()) continue; if (!c.dest_o->isPIObject()) continue;
c.dest_o->connectors.remove(src); c.dest_o->connectors.remove(this);
} }
for (int i = 0; i < src->connections.size_s(); ++i) for (int i = 0; i < connections.size_s(); ++i)
src->connections[i].destroy(); connections[i].destroy();
src->connections.clear(); connections.clear();
} }
@@ -444,8 +406,8 @@ void PIObject::updateConnectors() {
PIMutexLocker _ml(mutexObjects()); PIMutexLocker _ml(mutexObjects());
piForeach (PIObject * o, objects()) { piForeach (PIObject * o, objects()) {
if (o == this) continue; if (o == this) continue;
PIVector<__Connection> & oc(o->connections); PIVector<Connection> & oc(o->connections);
piForeach (__Connection & c, oc) piForeach (Connection & c, oc)
if (c.dest == this) if (c.dest == this)
connectors << o; connectors << o;
} }
@@ -606,7 +568,7 @@ void PIObject::dump(const PIString & line_prefix) const {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " connections {"; PICout(PICoutManipulators::AddNewLine) << line_prefix << " connections {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << connections.size_s(); PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << connections.size_s();
//printf("dump %d connections\n",connections.size()); //printf("dump %d connections\n",connections.size());
piForeachC (__Connection & c, connections) { piForeachC (Connection & c, connections) {
PIObject * dst = c.dest_o; PIObject * dst = c.dest_o;
__MetaFunc ef = methodEH(c.signal); __MetaFunc ef = methodEH(c.signal);
PIString src(c.event); PIString src(c.event);
@@ -679,41 +641,87 @@ void PIObject::__MetaData::addScope(const PIString & s, uint shash) {
} }
void PIObject::__Connection::destroy() {
void PIObject::Connection::destroy() {
if (functor) delete functor; if (functor) delete functor;
functor = nullptr; functor = nullptr;
} }
PIObject::Connection::Connection() {
slot = signal = dest = nullptr;
src_o = dest_o = performer = nullptr;
functor = nullptr;
eventID = 0;
args_count = 0;
}
bool PIObject::Connection::disconnect() {
if (!isValid() || !src_o) return false;
if (!src_o->isPIObject()) return false;
bool ndm = dest_o && (src_o != dest_o), ret = false, found = false;
if (dest_o) {
if (!dest_o->isPIObject()) ndm = false;
}
PIMutexLocker _ml(src_o->mutex_connect);
if (ndm) dest_o->mutex_connect.lock();
for (int i = 0; i < src_o->connections.size_s(); ++i) {
Connection & cc(src_o->connections[i]);
if (cc.eventID == eventID) {
if (dest_o && (cc.dest_o == dest_o)) {
if (cc.slot == slot)
found = true;
}
if (functor && (cc.functor == functor))
found = true;
}
if (found) {
src_o->connections[i].destroy();
src_o->connections.remove(i);
ret = true;
break;
}
}
if (dest_o) {
if (dest_o->isPIObject())
dest_o->updateConnectors();
}
if (ndm) dest_o->mutex_connect.unlock();
return ret;
}
PRIVATE_DEFINITION_START(PIObject::Deleter) PRIVATE_DEFINITION_START(PIObject::Deleter)
PIThread thread; PIThread thread;
PIConditionVariable cond_var; PIConditionVariable cond_var;
PIMutex cond_mutex, queue_mutex;
PIVector<PIObject*> obj_queue; PIVector<PIObject*> obj_queue;
PRIVATE_DEFINITION_END(PIObject::Deleter) PRIVATE_DEFINITION_END(PIObject::Deleter)
PIObject::Deleter::Deleter() { PIObject::Deleter::Deleter() {
//piCout << "Deleter start ..."; //piCout << "Deleter start ...";
stopping = started = posted = false; PRIVATE->thread.setSlot([this](){
CONNECTL(&(PRIVATE->thread), started, [this](){proc();}); PIVector<PIObject*> oq;
PRIVATE->thread.startOnce(); PRIVATE->thread.lock();
while (!started) while(PRIVATE->obj_queue.isEmpty()) PRIVATE->cond_var.wait(PRIVATE->thread.mutex());
piMSleep(1); oq.swap(PRIVATE->obj_queue);
PRIVATE->thread.unlock();
for (PIObject * o : oq) deleteObject(o);
});
PRIVATE->thread.start();
} }
PIObject::Deleter::~Deleter() { PIObject::Deleter::~Deleter() {
//piCout << "~Deleter ..."; //piCout << "~Deleter ...";
stopping = true; PRIVATE->thread.stop();
PRIVATE->cond_var.notifyAll(); PRIVATE->cond_var.notifyAll();
#ifndef WINDOWS PRIVATE->thread.waitForFinish();
while (PRIVATE->thread.isRunning()) for (PIObject * o : PRIVATE->obj_queue) deleteObject(o);
piMSleep(1);
#endif
deleteAll();
//piCout << "~Deleter ok"; //piCout << "~Deleter ok";
} }
@@ -727,58 +735,22 @@ PIObject::Deleter * PIObject::Deleter::instance() {
void PIObject::Deleter::post(PIObject * o) { void PIObject::Deleter::post(PIObject * o) {
if (!o->isPIObject()) return; if (!o->isPIObject()) return;
//piCout << "[Deleter] post" << o << "..."; //piCout << "[Deleter] post" << o << "...";
PRIVATE->queue_mutex.lock(); PRIVATE->thread.lock();
if (!PRIVATE->obj_queue.contains(o)) if (!PRIVATE->obj_queue.contains(o)) {
PRIVATE->obj_queue << o; PRIVATE->obj_queue << o;
PRIVATE->queue_mutex.unlock();
PRIVATE->cond_var.notifyAll(); PRIVATE->cond_var.notifyAll();
posted = true; }
PRIVATE->thread.unlock();
//piCout << "[Deleter] post" << o << "done"; //piCout << "[Deleter] post" << o << "done";
} }
void PIObject::Deleter::proc() {
//piCout << "[Deleter] proc start";
while (!stopping) {
//piMSleep(1);
//piCout << "[Deleter] proc wait ...";
if (posted) {
posted = false;
started = true;
} else {
PRIVATE->cond_mutex.lock();
started = true;
PRIVATE->cond_var.wait(PRIVATE->cond_mutex);
PRIVATE->cond_mutex.unlock();
}
//piCout << "[Deleter] proc wait done";
deleteAll();
}
//piCout << "[Deleter] proc end ok";
}
void PIObject::Deleter::deleteAll() {
PIVector<PIObject*> oq;
PRIVATE->queue_mutex.lock();
oq = PRIVATE->obj_queue;
//piCout << "[Deleter] deleteAll" << oq.size_s() << "...";
PRIVATE->obj_queue.clear();
PRIVATE->queue_mutex.unlock();
piForeach (PIObject * o, oq)
deleteObject(o);
}
void PIObject::Deleter::deleteObject(PIObject * o) { void PIObject::Deleter::deleteObject(PIObject * o) {
//piCout << "[Deleter] delete" << (uintptr_t)o << "..."; //piCout << "[Deleter] delete" << (uintptr_t)o << "...";
if (o->isPIObject()) { if (o->isPIObject()) {
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ..."; //piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ...";
while (o->isInEvent()) { while (o->isInEvent()) piMinSleep();
piMSleep(1);
}
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done"; //piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done";
if (o->isPIObject())
delete o; delete o;
} }
//piCout << "[Deleter] delete" << (uintptr_t)o << "done"; //piCout << "[Deleter] delete" << (uintptr_t)o << "done";

View File

@@ -50,6 +50,54 @@ public:
virtual ~PIObject(); virtual ~PIObject();
//! Helper class for obtain info about if connection successful and disconnect single connection
class PIP_EXPORT Connection {
friend class PIObject;
Connection(void * sl, void * si, const PIString & e = PIString(),
PIObject * s_o = nullptr, PIObject * d_o = nullptr,
void * d = nullptr, int ac = 0, PIObject * p = nullptr) {
slot = sl;
signal = si;
event = e;
eventID = e.hash();
src_o = s_o;
dest_o = d_o;
dest = d;
args_count = ac;
performer = p;
functor = 0;
}
void destroy();
void * slot;
void * signal;
std::function<void()> * functor;
PIString event;
uint eventID;
PIObject * src_o, * dest_o;
PIObject * performer;
void * dest;
int args_count;
public:
//! Contructs invalid %Connection
Connection();
//! Returns if %Connection is valid
bool isValid() const {return signal;}
//! Returns source object
PIObject * sourceObject() const {return src_o;}
//! Returns destination object or nullptr if this is lambda connection
PIObject * destinationObject() const {return dest_o;}
//! Returns performer object or nullptr if this is non-queued connection
PIObject * performerObject() const {return performer;}
//! Disconnect this %Connection, returns if operation successful
bool disconnect();
};
private: private:
uint _signature_; uint _signature_;
@@ -141,33 +189,38 @@ public:
PIString methodEHFromAddr(const void * addr) const; PIString methodEHFromAddr(const void * addr) const;
// / Direct connect // / Direct connect
static void piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc); static PIObject::Connection piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc);
static bool piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0); static PIObject::Connection piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0);
static bool piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc); static PIObject::Connection piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc);
template <typename INPUT, typename... TYPES> template <typename INPUT, typename... TYPES>
static std::function<void()> * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT functor) { static std::function<void()> * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT functor) {
return (std::function<void()>*)(new std::function<void(TYPES...)>(functor)); return (std::function<void()>*)(new std::function<void(TYPES...)>(functor));
} }
// / Through names and mixed
static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h); //! Disconnect object from all connections with event name "sig", connected to destination object "dest" and handler "ev_h"
static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h); void piDisconnect(const PIString & sig, PIObject * dest, void * ev_h) {piDisconnect(this, sig, dest, ev_h);}
static void piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h);
//! Disconnect object from all connections with event name "sig", connected to destination object "dest"
void piDisconnect(const PIString & sig, PIObject * dest) {piDisconnect(this, sig, dest);}
//! Disconnect object from all connections with event name "sig"
void piDisconnect(const PIString & sig) {piDisconnect(this, sig);}
//! Disconnect object "src" from all connections with event name "sig", connected to destination object "dest" and handler "ev_h"
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h); static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h);
//! Disconnect object "src" from all connections with event name "sig", connected to destination object "dest"
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest); static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest);
//! Disconnect object "src" from all connections with event name "sig" //! Disconnect object "src" from all connections with event name "sig"
static void piDisconnect(PIObject * src, const PIString & sig); static void piDisconnect(PIObject * src, const PIString & sig);
//! Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter
static void piDisconnect(PIObject * src);
// / Raise events // / Raise events
static void raiseEvent(PIObject * sender, const uint eventID) { static void raiseEvent(PIObject * sender, const uint eventID) {
for (int j = 0; j < sender->connections.size_s(); ++j) { for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]); Connection i(sender->connections[j]);
if (i.eventID != eventID) continue; if (i.eventID != eventID) continue;
if (i.functor) { if (i.functor) {
(*(i.functor))(); (*(i.functor))();
@@ -196,7 +249,7 @@ public:
template <typename T0> template <typename T0>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0()) { static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0()) {
for (int j = 0; j < sender->connections.size_s(); ++j) { for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]); Connection i(sender->connections[j]);
if (i.eventID != eventID) continue; if (i.eventID != eventID) continue;
if (i.functor) { if (i.functor) {
(*((std::function<void(T0)>*)i.functor))(v0); (*((std::function<void(T0)>*)i.functor))(v0);
@@ -227,7 +280,7 @@ public:
template <typename T0, typename T1> template <typename T0, typename T1>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1()) { static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1()) {
for (int j = 0; j < sender->connections.size_s(); ++j) { for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]); Connection i(sender->connections[j]);
if (i.eventID != eventID) continue; if (i.eventID != eventID) continue;
if (i.functor) { if (i.functor) {
(*((std::function<void(T0, T1)>*)i.functor))(v0, v1); (*((std::function<void(T0, T1)>*)i.functor))(v0, v1);
@@ -262,7 +315,7 @@ public:
template <typename T0, typename T1, typename T2> template <typename T0, typename T1, typename T2>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) { static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) {
for (int j = 0; j < sender->connections.size_s(); ++j) { for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]); Connection i(sender->connections[j]);
if (i.eventID != eventID) continue; if (i.eventID != eventID) continue;
if (i.functor) { if (i.functor) {
(*((std::function<void(T0, T1, T2)>*)i.functor))(v0, v1, v2); (*((std::function<void(T0, T1, T2)>*)i.functor))(v0, v1, v2);
@@ -299,7 +352,7 @@ public:
template <typename T0, typename T1, typename T2, typename T3> template <typename T0, typename T1, typename T2, typename T3>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) { static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) {
for (int j = 0; j < sender->connections.size_s(); ++j) { for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]); Connection i(sender->connections[j]);
if (i.eventID != eventID) continue; if (i.eventID != eventID) continue;
if (i.functor) { if (i.functor) {
(*((std::function<void(T0, T1, T2, T3)>*)i.functor))(v0, v1, v2, v3); (*((std::function<void(T0, T1, T2, T3)>*)i.functor))(v0, v1, v2, v3);
@@ -428,30 +481,6 @@ protected:
private: private:
struct __Connection {
__Connection(void * sl = 0, void * si = 0, const PIString & e = PIString(), PIObject * d_o = 0, void * d = 0, int ac = 0, PIObject * p = 0) {
slot = sl;
signal = si;
event = e;
eventID = e.hash();
dest_o = d_o;
dest = d;
args_count = ac;
performer = p;
functor = 0;
}
void destroy();
void * slot;
void * signal;
std::function<void()> * functor;
PIString event;
uint eventID;
PIObject * dest_o;
PIObject * performer;
void * dest;
int args_count;
};
struct __QueuedEvent { struct __QueuedEvent {
__QueuedEvent(void * sl = 0, void * d = 0, PIObject * d_o = 0, PIObject * s = 0, const PIVector<PIVariantSimple> & v = PIVector<PIVariantSimple>()) { __QueuedEvent(void * sl = 0, void * d = 0, PIObject * d_o = 0, PIObject * s = 0, const PIVector<PIVariantSimple> & v = PIVector<PIVariantSimple>()) {
slot = sl; slot = sl;
@@ -474,10 +503,7 @@ private:
static Deleter * instance(); static Deleter * instance();
void post(PIObject * o); void post(PIObject * o);
private: private:
void proc();
void deleteAll();
void deleteObject(PIObject * o); void deleteObject(PIObject * o);
std::atomic_bool stopping, started, posted;
PRIVATE_DECLARATION(PIP_EXPORT) PRIVATE_DECLARATION(PIP_EXPORT)
}; };
@@ -488,6 +514,8 @@ private:
PIVector<__MetaFunc> findEH(const PIString & name) const; PIVector<__MetaFunc> findEH(const PIString & name) const;
__MetaFunc methodEH(const void * addr) const; __MetaFunc methodEH(const void * addr) const;
void updateConnectors(); void updateConnectors();
void piDisconnectAll();
void postQueuedEvent(const __QueuedEvent & e); void postQueuedEvent(const __QueuedEvent & e);
void eventBegin() {in_event_cnt++;} void eventBegin() {in_event_cnt++;}
void eventEnd () {in_event_cnt--;} void eventEnd () {in_event_cnt--;}
@@ -500,7 +528,7 @@ private:
static void callAddrV(void * slot, void * obj, int args, const PIVector<PIVariantSimple> & vl); static void callAddrV(void * slot, void * obj, int args, const PIVector<PIVariantSimple> & vl);
PIVector<__Connection> connections; PIVector<Connection> connections;
PIMap<uint, PIPair<PIString, PIVariant> > properties_; PIMap<uint, PIPair<PIString, PIVariant> > properties_;
PISet<PIObject * > connectors; PISet<PIObject * > connectors;
PIVector<__QueuedEvent> events_queue; PIVector<__QueuedEvent> events_queue;

View File

@@ -102,28 +102,36 @@
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\". \"Event\" and \"handler\" must has equal argument lists. /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\". \"Event\" and \"handler\" must has equal argument lists.
/// Returns PIObject::Connection
#define CONNECTU(src, event, dest, handler) #define CONNECTU(src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\". /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\".
/// Event handler will be executed by \"performer\". \"Event\" and \"handler\" must has equal argument lists. /// Event handler will be executed by \"performer\". \"Event\" and \"handler\" must has equal argument lists.
/// Returns PIObject::Connection
#define CONNECTU_QUEUED(src, event, dest, handler, performer) #define CONNECTU_QUEUED(src, event, dest, handler, performer)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to lambda-expression \"functor\". \"Event\" and \"functor\" must has equal argument lists. /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to lambda-expression \"functor\". \"Event\" and \"functor\" must has equal argument lists.
/// Returns PIObject::Connection
#define CONNECTL(src, event, functor) #define CONNECTL(src, event, functor)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
/// Returns PIObject::Connection
#define CONNECT0(ret, src, event, dest, handler) #define CONNECT0(ret, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
/// Returns PIObject::Connection
#define CONNECT1(ret, type0, src, event, dest, handler) #define CONNECT1(ret, type0, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
/// Returns PIObject::Connection
#define CONNECT2(ret, type0, type1, src, event, dest, handler) #define CONNECT2(ret, type0, type1, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
/// Returns PIObject::Connection
#define CONNECT3(ret, type0, type1, type2, src, event, dest, handler) #define CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists /// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists.
/// Returns PIObject::Connection
#define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler) #define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
/// \relatesalso PIObject @brief CONNECT is synonym of CONNECT0 /// \relatesalso PIObject @brief CONNECT is synonym of CONNECT0

View File

@@ -469,13 +469,3 @@ PICout operator <<(PICout s, const PIDateTime & v) {
return s; return s;
} }
#ifdef WINDOWS
void msleep(int msecs) {Sleep(msecs);}
#else
# ifdef FREERTOS
void msleep(int msecs) {vTaskDelay(msecs / portTICK_PERIOD_MS);}
# else
void msleep(int msecs) {usleep(msecs * 1000);}
# endif
#endif

View File

@@ -29,8 +29,6 @@
#ifdef QNX #ifdef QNX
# include <time.h> # include <time.h>
#endif #endif
//! @brief Sleep for "msecs" milliseconds
PIP_EXPORT void msleep(int msecs);
/*! @brief Precise sleep for "usecs" microseconds /*! @brief Precise sleep for "usecs" microseconds
* \details This function consider \c "usleep" offset * \details This function consider \c "usleep" offset
@@ -48,6 +46,8 @@ inline void piMSleep(double msecs) {piUSleep(int(msecs * 1000.));} // on !Window
* \details This function exec \a piUSleep (msecs * 1000000). */ * \details This function exec \a piUSleep (msecs * 1000000). */
inline void piSleep(double secs) {piUSleep(int(secs * 1000000.));} // on !Windows consider constant "usleep" offset inline void piSleep(double secs) {piUSleep(int(secs * 1000000.));} // on !Windows consider constant "usleep" offset
//! Shortest available on current system sleep
inline void piMinSleep() {piMSleep(PIP_MIN_MSLEEP);}

View File

@@ -99,9 +99,6 @@ struct PIP_EXPORT Enum {
* @brief Make vector of Enum names * @brief Make vector of Enum names
*/ */
PIStringList names() const; PIStringList names() const;
PIString enum_name;
PIString selected;
PIVector<Enumerator> enum_list;
/** /**
* @brief Add PIVariantTypes::Enumerator to Enum * @brief Add PIVariantTypes::Enumerator to Enum
@@ -119,6 +116,15 @@ struct PIP_EXPORT Enum {
* @brief Add PIVariantTypes::Enumerator element for each name in vector * @brief Add PIVariantTypes::Enumerator element for each name in vector
*/ */
Enum & operator <<(const PIStringList & v); Enum & operator <<(const PIStringList & v);
/**
* @brief Return true if Enum is empty
*/
bool isEmpty() const {return enum_list.isEmpty();}
PIString enum_name;
PIString selected;
PIVector<Enumerator> enum_list;
}; };
struct PIP_EXPORT File { struct PIP_EXPORT File {

View File

@@ -58,6 +58,9 @@ public:
//! Generate hash from bytearray //! Generate hash from bytearray
static PIByteArray hash(const PIByteArray & data); static PIByteArray hash(const PIByteArray & data);
//! Generate hash from bytearray
static PIByteArray hash(const PIByteArray & data, const unsigned char * key, size_t keylen);
//! Returns hash size //! Returns hash size
static size_t sizeHash(); static size_t sizeHash();

View File

@@ -181,7 +181,7 @@ bool PIBinaryLog::threadedRead(uchar *readed, int size) {
pausemutex.lock(); pausemutex.lock();
if (is_pause) { if (is_pause) {
pausemutex.unlock(); pausemutex.unlock();
piMSleep(100); piMSleep(100); // TODO: rewrite with condvar
return false; return false;
} else if (pause_time > PISystemTime()) { } else if (pause_time > PISystemTime()) {
startlogtime += pause_time; startlogtime += pause_time;
@@ -204,22 +204,22 @@ bool PIBinaryLog::threadedRead(uchar *readed, int size) {
int dtc; int dtc;
if (is_started) { if (is_started) {
if (is_pause) { if (is_pause) {
piMSleep(100); piMSleep(100); // TODO: rewrite with condvar
return false; return false;
} }
if (delay > 0) { if (delay > 0) {
cdelay = delay * play_speed; cdelay = delay * play_speed;// TODO: rewrite with condvar
dtc = int(cdelay) /100; dtc = int(cdelay) / 100;// TODO: rewrite with condvar
if (play_speed <= 0.) dtc = 2; if (play_speed <= 0.) dtc = 2;
//piCout << play_speed << dtc; //piCout << play_speed << dtc;
for (int j=0; j<dtc; j++) { for (int j=0; j<dtc; j++) {
cdelay = delay * play_speed; cdelay = delay * play_speed;// TODO: rewrite with condvar
dtc = int(cdelay) /100; dtc = int(cdelay) / 100;// TODO: rewrite with condvar
piMSleep(100); piMSleep(100);// TODO: rewrite with condvar
if (play_speed <= 0.) {dtc = 2; j = 0;} if (play_speed <= 0.) {dtc = 2; j = 0;}
//piCout << " " << play_speed << dtc << j; //piCout << " " << play_speed << dtc << j;
} }
cdelay = cdelay - dtc*100; cdelay = cdelay - dtc*100;// TODO: rewrite with condvar
PISystemTime::fromMilliseconds(cdelay).sleep(); PISystemTime::fromMilliseconds(cdelay).sleep();
} }
} else is_started = true; } else is_started = true;
@@ -228,7 +228,7 @@ bool PIBinaryLog::threadedRead(uchar *readed, int size) {
case PlayStaticDelay: case PlayStaticDelay:
if (is_started) { if (is_started) {
if (is_pause) { if (is_pause) {
piMSleep(100); piMSleep(100);// TODO: rewrite with condvar
return false; return false;
} }
play_delay.sleep(); play_delay.sleep();
@@ -357,7 +357,9 @@ PIByteArray PIBinaryLog::readBinLog(int id, PISystemTime * time, int * readed_id
if (readed_id) *readed_id = br.id; if (readed_id) *readed_id = br.id;
return br.data; return br.data;
} }
logmutex.lock();
while (br.id != id && !isEnd()) br = readRecord(); while (br.id != id && !isEnd()) br = readRecord();
logmutex.unlock();
if (br.id == -1) { if (br.id == -1) {
piCoutObj << "End of BinLog file"; piCoutObj << "End of BinLog file";
fileEnd(); fileEnd();
@@ -579,6 +581,7 @@ void PIBinaryLog::parseLog(PIFile * f, PIBinaryLog::BinLogInfo * info, PIVector<
if (info) { if (info) {
BinLogIndex bl_ind; BinLogIndex bl_ind;
bl_ind.id = br.id; bl_ind.id = br.id;
bl_ind.data_size = br.size;
bl_ind.pos = f->pos() - br.size - hdr_size; bl_ind.pos = f->pos() - br.size - hdr_size;
bl_ind.timestamp = br.timestamp; bl_ind.timestamp = br.timestamp;
index->append(bl_ind); index->append(bl_ind);
@@ -665,9 +668,22 @@ bool PIBinaryLog::createIndex() {
} }
int PIBinaryLog::posForTime(const PISystemTime & time) {
int ci = -1;
for (uint i = 0; i < index.size(); i++) {
if (time <= index[i].timestamp && (filterID.contains(index[i].id) || filterID.isEmpty())) {
ci = i;
break;
}
}
return ci;
}
void PIBinaryLog::seekTo(int rindex) { void PIBinaryLog::seekTo(int rindex) {
// piCoutObj << "seekTo"; // piCoutObj << "seekTo";
logmutex.lock(); logmutex.lock();
pausemutex.lock();
if (rindex < index.size_s() && rindex >= 0) { if (rindex < index.size_s() && rindex >= 0) {
file.seek(index[rindex].pos); file.seek(index[rindex].pos);
moveIndex(index_pos.value(file.pos(), -1)); moveIndex(index_pos.value(file.pos(), -1));
@@ -679,18 +695,13 @@ void PIBinaryLog::seekTo(int rindex) {
} }
} }
// piCoutObj << "seekTo done"; // piCoutObj << "seekTo done";
pausemutex.unlock();
logmutex.unlock(); logmutex.unlock();
} }
bool PIBinaryLog::seek(const PISystemTime & time) { bool PIBinaryLog::seek(const PISystemTime & time) {
int ci = -1; int ci = posForTime(time);
for (uint i=0; i<index.size(); i++) {
if (time <= index[i].timestamp && (filterID.contains(index[i].id) || filterID.isEmpty())) {
ci = i;
break;
}
}
if (ci >= 0) { if (ci >= 0) {
seekTo(ci); seekTo(ci);
return true; return true;

View File

@@ -76,6 +76,7 @@ public:
//! @brief Struct contains position, ID and timestamp of record in file //! @brief Struct contains position, ID and timestamp of record in file
struct PIP_EXPORT BinLogIndex { struct PIP_EXPORT BinLogIndex {
int id; int id;
int data_size;
llong pos; llong pos;
PISystemTime timestamp; PISystemTime timestamp;
}; };
@@ -201,6 +202,9 @@ public:
//! Returns timestamp of last readed record //! Returns timestamp of last readed record
PISystemTime lastReadedTimestamp() const {return lastrecord.timestamp;} PISystemTime lastReadedTimestamp() const {return lastrecord.timestamp;}
//! Returns timestamp of log start
PISystemTime logStartTimestamp() const {return startlogtime;}
//!Set custom file header, you can get it back when read this binlog //!Set custom file header, you can get it back when read this binlog
void setHeader(const PIByteArray & header); void setHeader(const PIByteArray & header);
@@ -233,6 +237,9 @@ public:
//! Return if current binlog file is indexed //! Return if current binlog file is indexed
bool isIndexed() {return is_indexed;} bool isIndexed() {return is_indexed;}
//! Find nearest record of time \"time\". Returns -1 if not indexed or time less than first record
int posForTime(const PISystemTime & time);
//! Go to record #index //! Go to record #index
void seekTo(int rindex); void seekTo(int rindex);

View File

@@ -686,7 +686,7 @@ int PIEthernet::readDevice(void * read_to, int max_size) {
s = accept(sock, (sockaddr * )&client_addr, &slen); s = accept(sock, (sockaddr * )&client_addr, &slen);
if (s == -1) { if (s == -1) {
//piCoutObj << "Can`t accept new connection, " << ethErrorString(); //piCoutObj << "Can`t accept new connection, " << ethErrorString();
msleep(PIP_MIN_MSLEEP); piMinSleep();
return -1; return -1;
} }
rs = ethRecv(s, read_to, max_size); rs = ethRecv(s, read_to, max_size);
@@ -788,7 +788,7 @@ int PIEthernet::writeDevice(const void * data, int max_size) {
//piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "..."; //piCoutObj << "connect SingleTCP" << ip_s << ":" << port_s << "...";
if (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) != 0) { if (::connect(sock, (sockaddr * )&PRIVATE->addr_, sizeof(PRIVATE->addr_)) != 0) {
//piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString(); //piCoutObj << "Can`t connect to " << ip_s << ":" << port_s << ", " << ethErrorString();
msleep(PIP_MIN_MSLEEP); piMinSleep();
return -1; return -1;
} }
//piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ..."; //piCoutObj << "ok, write SingleTCP" << int(data) << max_size << "bytes ...";
@@ -993,6 +993,7 @@ void PIEthernet::configureFromVariantDevice(const PIPropertyStorage & d) {
PIEthernet::InterfaceList PIEthernet::interfaces() { PIEthernet::InterfaceList PIEthernet::interfaces() {
//piCout << "PIEthernet::interfaces()";
PIEthernet::InterfaceList il; PIEthernet::InterfaceList il;
Interface ci; Interface ci;
ci.index = -1; ci.index = -1;
@@ -1039,8 +1040,16 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
} }
pAdapter = pAdapter->Next; pAdapter = pAdapter->Next;
} }
} else } else {
switch (ret) {
case ERROR_NO_DATA: break;
case ERROR_NOT_SUPPORTED:
piCout << "[PIEthernet] GetAdaptersInfo not supported";
break;
default:
piCout << "[PIEthernet] GetAdaptersInfo failed with error:" << ret; piCout << "[PIEthernet] GetAdaptersInfo failed with error:" << ret;
}
}
if (pAdapterInfo) if (pAdapterInfo)
HeapFree(GetProcessHeap(), 0, (pAdapterInfo)); HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
#else #else

View File

@@ -148,7 +148,17 @@ PIFile::PIFile(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(p
bool PIFile::openTemporary(PIIODevice::DeviceMode mode) { bool PIFile::openTemporary(PIIODevice::DeviceMode mode) {
return open(PIString(tmpnam(0)), mode); PIString tp;
#ifdef WINDOWS
tp = PIDir::temporary().path() + PIDir::separator + "file" + PIString::fromNumber(randomi());
#else
char * rc = tmpnam(0);
if (!rc) return false;
tp = rc;
#endif
while (isExists(tp))
tp += PIString::fromNumber(randomi() % 10);
return open(tp, mode);
} }

View File

@@ -85,6 +85,7 @@ public:
}; };
//! Constructs a file with path "path" and open mode "mode" //! Constructs a file with path "path" and open mode "mode"
//! If "path" is not empty then open file
explicit PIFile(const PIString & path, DeviceMode mode = ReadWrite); explicit PIFile(const PIString & path, DeviceMode mode = ReadWrite);

View File

@@ -163,7 +163,7 @@ bool stopThread(PIThread * t, bool hard) {
return true; return true;
} else { } else {
t->stop(); t->stop();
if (t->waitForFinish(10000)) { if (!t->waitForFinish(10000)) {
t->terminate(); t->terminate();
return true; return true;
} }
@@ -239,7 +239,7 @@ void PIIODevice::check_start(void * data, int delim) {
//cout << "check " << tread_started_ << endl; //cout << "check " << tread_started_ << endl;
if (open()) { if (open()) {
thread_started_ = true; thread_started_ = true;
timer.stop(); timer.stop(false);
} }
} }
@@ -254,7 +254,7 @@ void PIIODevice::write_func() {
int ret = write(item.first); int ret = write(item.first);
threadedWriteEvent(item.second, ret); threadedWriteEvent(item.second, ret);
} }
msleep(PIP_MIN_MSLEEP); piMinSleep();
} }
} }
@@ -338,7 +338,7 @@ PIByteArray PIIODevice::readForTime(double timeout_ms) {
tm.reset(); tm.reset();
while (tm.elapsed_m() < timeout_ms) { while (tm.elapsed_m() < timeout_ms) {
ret = read(td, threaded_read_buffer_size); ret = read(td, threaded_read_buffer_size);
if (ret <= 0) msleep(PIP_MIN_MSLEEP); if (ret <= 0) piMinSleep();
else str.append(td, ret); else str.append(td, ret);
} }
delete[] td; delete[] td;

View File

@@ -289,6 +289,39 @@ bool PISerial::isRNG() const {return isBit(TIOCM_RNG, "RNG");}
bool PISerial::isDSR() const {return isBit(TIOCM_DSR, "DSR");} bool PISerial::isDSR() const {return isBit(TIOCM_DSR, "DSR");}
bool PISerial::setBreak(bool enabled) {
if (fd < 0) {
piCoutObj << "sendBreak error: \"" << path() << "\" is not opened!";
return false;
}
#ifdef WINDOWS
if (enabled) {
if (!SetCommBreak(PRIVATE->hCom)) {
piCoutObj << "setBreak error: " << errorString();
return false;
} else {
return true;
}
} else {
if (!ClearCommBreak(PRIVATE->hCom)) {
piCoutObj << "setBreak error: " << errorString();
return false;
} else {
return true;
}
}
#else
if (ioctl(fd, enabled ? TIOCSBRK : TIOCCBRK) < 0) {
piCoutObj << "setBreak error: " << errorString();
return false;
} else {
return true;
}
#endif
return false;
}
bool PISerial::setBit(int bit, bool on, const PIString & bname) { bool PISerial::setBit(int bit, bool on, const PIString & bname) {
if (fd < 0) { if (fd < 0) {
piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!"; piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!";
@@ -356,6 +389,9 @@ int PISerial::convertSpeed(PISerial::Speed speed) {
case S2400: return B2400; case S2400: return B2400;
case S4800: return B4800; case S4800: return B4800;
case S9600: return B9600; case S9600: return B9600;
#ifdef WINDOWS
case S14400: return B14400;
#endif
case S19200: return B19200; case S19200: return B19200;
case S38400: return B38400; case S38400: return B38400;
case S57600: return B57600; case S57600: return B57600;
@@ -398,7 +434,7 @@ bool PISerial::read(void * data, int size, double timeout_ms) {
while (all < size && tm_.elapsed_m() < timeout_ms) { while (all < size && tm_.elapsed_m() < timeout_ms) {
ret = readDevice(&((uchar * )data)[all], size - all); ret = readDevice(&((uchar * )data)[all], size - all);
if (ret > 0) all += ret; if (ret > 0) all += ret;
else msleep(PIP_MIN_MSLEEP); else piMinSleep();
} }
setOption(BlockingRead, br); setOption(BlockingRead, br);
received(data, all); received(data, all);
@@ -437,13 +473,13 @@ PIString PISerial::read(int size, double timeout_ms) {
if (size <= 0) { if (size <= 0) {
while (tm_.elapsed_m() < timeout_ms) { while (tm_.elapsed_m() < timeout_ms) {
ret = readDevice(td, 1024); ret = readDevice(td, 1024);
if (ret <= 0) msleep(PIP_MIN_MSLEEP); if (ret <= 0) piMinSleep();
else str << PIString((char*)td, ret); else str << PIString((char*)td, ret);
} }
} else { } else {
while (all < size && tm_.elapsed_m() < timeout_ms) { while (all < size && tm_.elapsed_m() < timeout_ms) {
ret = readDevice(td, size - all); ret = readDevice(td, size - all);
if (ret <= 0) msleep(PIP_MIN_MSLEEP); if (ret <= 0) piMinSleep();
else { else {
str << PIString((char*)td, ret); str << PIString((char*)td, ret);
all += ret; all += ret;
@@ -457,7 +493,7 @@ PIString PISerial::read(int size, double timeout_ms) {
str << PIString((char*)td, all); str << PIString((char*)td, all);
while (all < size) { while (all < size) {
ret = readDevice(td, size - all); ret = readDevice(td, size - all);
if (ret <= 0) msleep(PIP_MIN_MSLEEP); if (ret <= 0) piMinSleep();
else { else {
str << PIString((char*)td, ret); str << PIString((char*)td, ret);
all += ret; all += ret;
@@ -489,13 +525,13 @@ PIByteArray PISerial::readData(int size, double timeout_ms) {
if (size <= 0) { if (size <= 0) {
while (tm_.elapsed_m() < timeout_ms) { while (tm_.elapsed_m() < timeout_ms) {
ret = readDevice(td, 1024); ret = readDevice(td, 1024);
if (ret <= 0) msleep(PIP_MIN_MSLEEP); if (ret <= 0) piMinSleep();
else str.append(td, ret); else str.append(td, ret);
} }
} else { } else {
while (all < size && tm_.elapsed_m() < timeout_ms) { while (all < size && tm_.elapsed_m() < timeout_ms) {
ret = readDevice(td, size - all); ret = readDevice(td, size - all);
if (ret <= 0) msleep(PIP_MIN_MSLEEP); if (ret <= 0) piMinSleep();
else { else {
str.append(td, ret); str.append(td, ret);
all += ret; all += ret;
@@ -509,7 +545,7 @@ PIByteArray PISerial::readData(int size, double timeout_ms) {
str.append(td, all); str.append(td, all);
while (all < size) { while (all < size) {
ret = readDevice(td, size - all); ret = readDevice(td, size - all);
if (ret <= 0) msleep(PIP_MIN_MSLEEP); if (ret <= 0) piMinSleep();
else { else {
str.append(td, ret); str.append(td, ret);
all += ret; all += ret;
@@ -846,9 +882,13 @@ void PISerial::configureFromVariantDevice(const PIPropertyStorage & d) {
PIVector<int> PISerial::availableSpeeds() { PIVector<int> PISerial::availableSpeeds() {
PIVector<int> spds; PIVector<int> spds;
spds << 50 << 75 << 110 << 300 << 600 << 1200 << 2400 << 4800 << spds << 50 << 75 << 110 << 300 << 600 << 1200 << 2400 << 4800 <<
9600 << 19200 << 38400 << 57600 << 115200 << 230400 << 460800 << 9600 <<
500000 << 576000 << 921600 << 1000000 << 1152000 << 1500000 << #ifdef WINDOWS
2000000 << 2500000 << 3000000 << 3500000 << 4000000; 14400 <<
#endif
19200 << 38400 << 57600 << 115200 << 230400 <<
460800 << 500000 << 576000 << 921600 << 1000000 << 1152000 <<
1500000 << 2000000 << 2500000 << 3000000 << 3500000 << 4000000;
return spds; return spds;
} }

View File

@@ -52,6 +52,7 @@ public:
S2400 /*! 2400 baud */ = 2400, S2400 /*! 2400 baud */ = 2400,
S4800 /*! 4800 baud */ = 4800, S4800 /*! 4800 baud */ = 4800,
S9600 /*! 9600 baud */ = 9600, S9600 /*! 9600 baud */ = 9600,
S14400 /*! 14400 baud */ = 14400,
S19200 /*! 19200 baud */ = 19200, S19200 /*! 19200 baud */ = 19200,
S38400 /*! 38400 baud */ = 38400, S38400 /*! 38400 baud */ = 38400,
S57600 /*! 57600 baud */ = 57600, S57600 /*! 57600 baud */ = 57600,
@@ -159,6 +160,12 @@ public:
bool isRNG() const; bool isRNG() const;
bool isDSR() const; bool isDSR() const;
//! Switch transmission line in break if enabled.
//! i.e. sends a continuous stream of zero bits.
//! If successful, returns true; otherwise returns false.
//! The serial port has to be open before trying to send a break duration; otherwise returns false
bool setBreak(bool enabled);
void setVTime(int t) {vtime = t; applySettings();} void setVTime(int t) {vtime = t; applySettings();}
//! Returns device name //! Returns device name

View File

@@ -346,7 +346,7 @@ bool PIBaseTransfer::send_process() {
if (chk == 0) return finish_send(true); if (chk == 0) return finish_send(true);
if (chk != prev_chk) rtm.reset(); if (chk != prev_chk) rtm.reset();
else if (rtm.elapsed_m() < 100) { else if (rtm.elapsed_m() < 100) {
piMSleep(PIP_MIN_MSLEEP); piMinSleep();
continue; continue;
} }
if (is_pause) { if (is_pause) {
@@ -507,7 +507,7 @@ bool PIBaseTransfer::getStartRequest() {
return true; return true;
} }
mutex_session.unlock(); mutex_session.unlock();
piMSleep(PIP_MIN_MSLEEP); piMinSleep();
} }
return false; return false;
} }

View File

@@ -36,22 +36,6 @@ public:
//! Contructs packer and try to assign \"dev\" //! Contructs packer and try to assign \"dev\"
PIStreamPacker(PIIODevice * dev = 0); PIStreamPacker(PIIODevice * dev = 0);
//! Progress info
struct PIP_IO_UTILS_EXPORT Progress {
Progress();
//! Is send/receive in progress
bool active;
//! Overall send/receive packet size
int bytes_all;
//! Current send/receive size
int bytes_current;
//! Current send/receive progress from 0 to 1
double progress;
};
//! Set maximum size of single packet //! Set maximum size of single packet
void setMaxPacketSize(int max_size) {max_packet_size = max_size;} void setMaxPacketSize(int max_size) {max_packet_size = max_size;}
@@ -83,6 +67,8 @@ public:
bool cryptSizeEnabled() const {return crypt_size;} bool cryptSizeEnabled() const {return crypt_size;}
void setCryptSizeEnabled(bool on); void setCryptSizeEnabled(bool on);
void clear();
//! Prepare data for send and raise \a sendRequest() events //! Prepare data for send and raise \a sendRequest() events
void send(const PIByteArray & data); void send(const PIByteArray & data);
@@ -97,12 +83,6 @@ public:
//! and \a sendRequest() event to \"dev\" \a PIIODevice::write() handler //! and \a sendRequest() event to \"dev\" \a PIIODevice::write() handler
void assignDevice(PIIODevice * dev); void assignDevice(PIIODevice * dev);
//! Returns \a Progress info about sending
Progress progressSend() const;
//! Returns \a Progress info about receiving
Progress progressReceive() const;
EVENT1(packetReceiveEvent, PIByteArray &, data) EVENT1(packetReceiveEvent, PIByteArray &, data)
EVENT1(sendRequest, PIByteArray, data) EVENT1(sendRequest, PIByteArray, data)
@@ -139,7 +119,6 @@ private:
int packet_size, crypt_frag_size; int packet_size, crypt_frag_size;
ushort packet_sign; ushort packet_sign;
int max_packet_size, size_crypted_size; int max_packet_size, size_crypted_size;
Progress prog_s, prog_r;
mutable PIMutex prog_s_mutex, prog_r_mutex; mutable PIMutex prog_s_mutex, prog_r_mutex;
}; };

View File

@@ -66,7 +66,7 @@ void PIProcess::exec_() {
startOnce(); startOnce();
//cout << "exec wait" << endl; //cout << "exec wait" << endl;
while (!is_exec) while (!is_exec)
msleep(PIP_MIN_MSLEEP); piMinSleep();
//cout << "exec end" << endl; //cout << "exec end" << endl;
} }
@@ -172,7 +172,7 @@ void PIProcess::startProc(bool detached) {
if (execve(str.data(), a, e) < 0) if (execve(str.data(), a, e) < 0)
piCoutObj << "\"execve" << str << args << "\" error :" << errorString(); piCoutObj << "\"execve" << str << args << "\" error :" << errorString();
} else { } else {
msleep(PIP_MIN_MSLEEP); piMinSleep;
//cout << "wait" << endl; //cout << "wait" << endl;
if (!detached) { if (!detached) {
wait(&exit_code); wait(&exit_code);

View File

@@ -259,7 +259,7 @@ uint PISystemInfo::machineID() {
if (ret == 0) { if (ret == 0) {
CRC_32 crc = standardCRC_32(); CRC_32 crc = standardCRC_32();
ret = crc.calculate(machineKey().toByteArray()); ret = crc.calculate(machineKey().toByteArray());
piCout << "machineID \"" << machineKey() << "\" =" << PICoutManipulators::Hex << ret; //piCout << "machineID \"" << machineKey() << "\" =" << PICoutManipulators::Hex << ret;
} }
return ret; return ret;
} }

View File

@@ -145,9 +145,9 @@ bool PISystemMonitor::startOnSelf(int interval_ms) {
PIVector<PISystemMonitor::ThreadStats> PISystemMonitor::threadsStatistic() const { PIVector<PISystemMonitor::ThreadStats> PISystemMonitor::threadsStatistic() const {
mutex_.lock(); lock();
PIVector<PISystemMonitor::ThreadStats> ret = cur_ts; PIVector<PISystemMonitor::ThreadStats> ret = cur_ts;
mutex_.unlock(); unlock();
return ret; return ret;
} }
@@ -341,9 +341,9 @@ void PISystemMonitor::run() {
//piCout << ts_new.cpu_load_user; //piCout << ts_new.cpu_load_user;
} }
last_tm = cur_tm; last_tm = cur_tm;
mutex_.lock(); lock();
cur_ts = cur_tm.values(); cur_ts = cur_tm.values();
mutex_.unlock(); unlock();
tstat.ram_total = totalRAM(); tstat.ram_total = totalRAM();
tstat.ram_used = usedRAM(); tstat.ram_used = usedRAM();
tstat.ram_free = freeRAM(); tstat.ram_free = freeRAM();

View File

@@ -36,7 +36,6 @@ PRIVATE_DEFINITION_START(PIConditionVariable)
#else #else
pthread_cond_t nativeHandle; pthread_cond_t nativeHandle;
#endif #endif
bool isDestroying;
PRIVATE_DEFINITION_END(PIConditionVariable) PRIVATE_DEFINITION_END(PIConditionVariable)
@@ -44,7 +43,6 @@ PIConditionVariable::PIConditionVariable() {
#ifdef WINDOWS #ifdef WINDOWS
InitializeConditionVariable(&PRIVATE->nativeHandle); InitializeConditionVariable(&PRIVATE->nativeHandle);
#else #else
PRIVATE->isDestroying = false;
pthread_condattr_t condattr; pthread_condattr_t condattr;
pthread_condattr_init(&condattr); pthread_condattr_init(&condattr);
@@ -84,7 +82,6 @@ void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& conditi
#else #else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle()); pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
#endif #endif
if (PRIVATE->isDestroying) return;
} }
} }
@@ -100,7 +97,6 @@ bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
st.toTimespec(&expire_ts); st.toTimespec(&expire_ts);
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) == 0; isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) == 0;
#endif #endif
if (PRIVATE->isDestroying) return false;
return isNotTimeout; return isNotTimeout;
} }
@@ -127,7 +123,6 @@ bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::functio
bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) != 0; bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) != 0;
#endif #endif
if (isTimeout) return false; if (isTimeout) return false;
if (PRIVATE->isDestroying) return false;
} }
return true; return true;
} }

View File

@@ -162,7 +162,7 @@ private:
return; return;
} }
if (ret > 0) { if (ret > 0) {
piMSleep(PIP_MIN_MSLEEP); piMinSleep();
return; return;
} }
diag_.received(1); diag_.received(1);

View File

@@ -25,6 +25,8 @@
#include "pithread.h" #include "pithread.h"
#include "piqueue.h" #include "piqueue.h"
#include "piconditionvar.h"
template <typename Tin, typename Tout> template <typename Tin, typename Tout>
class PIPipelineThread : public PIThread class PIPipelineThread : public PIThread
@@ -35,10 +37,10 @@ public:
cnt = 0; cnt = 0;
max_size = 0; max_size = 0;
wait_next_pipe = false; wait_next_pipe = false;
next_overload = false;
} }
~PIPipelineThread() { ~PIPipelineThread() {
stop(); stop();
cv.notifyAll();
if (!waitForFinish(1000)) { if (!waitForFinish(1000)) {
piCoutObj << "terminating self thread"; piCoutObj << "terminating self thread";
terminate(); terminate();
@@ -46,21 +48,27 @@ public:
} }
template <typename T> template <typename T>
void connectTo(PIPipelineThread<Tout, T> * next) { void connectTo(PIPipelineThread<Tout, T> * next) {
CONNECT2(void, Tout, bool *, this, calculated, next, enqueue) CONNECT3(void, Tout, bool, bool *, this, calculated, next, enqueue)
} }
EVENT2(calculated, const Tout &, v, bool *, overload) EVENT3(calculated, const Tout &, v, bool, wait, bool *, overload)
void enqueue(const Tin &v) {enqueue(v, 0);} EVENT_HANDLER3(void, enqueue, const Tin &, v, bool, wait, bool *, overload) {
EVENT_HANDLER2(void, enqueue, const Tin &, v, bool *, overload) {
mutex.lock(); mutex.lock();
//piCoutObj << "enque" << overload; //piCoutObj << "enque" << overload;
if (wait && max_size != 0) {
mutex_wait.lock();
while (in.size() >= max_size) cv_wait.wait(mutex_wait);
mutex_wait.unlock();
}
if (max_size == 0 || in.size() < max_size) { if (max_size == 0 || in.size() < max_size) {
in.enqueue(v); in.enqueue(v);
cv.notifyAll();
if (overload) *overload = false; if (overload) *overload = false;
} else { } else {
if (overload) *overload = true; if (overload) *overload = true;
} }
mutex.unlock(); mutex.unlock();
} }
void enqueue(const Tin &v, bool wait = false) {enqueue(v, wait, nullptr);}
const ullong * counterPtr() const {return &cnt;} const ullong * counterPtr() const {return &cnt;}
ullong counter() const {return cnt;} ullong counter() const {return cnt;}
bool isEmpty() { bool isEmpty() {
@@ -79,15 +87,18 @@ public:
} }
void clear() { void clear() {
mutex.lock(); mutex.lock();
mutex_wait.lock();
in.clear(); in.clear();
next_overload = false; cv_wait.notifyAll();
mutex_wait.unlock();
mutex.unlock(); mutex.unlock();
} }
void stopCalc(int wait_delay = 100) { void stopCalc(int wait_delay = 100) {
if (isRunning()) { if (isRunning()) {
stop(); stop();
cv.notifyAll();
if (!waitForFinish(wait_delay)) { if (!waitForFinish(wait_delay)) {
mutex_l.unlock(); mutex_last.unlock();
mutex.unlock(); mutex.unlock();
terminate(); terminate();
} }
@@ -95,18 +106,14 @@ public:
} }
Tout getLast() { Tout getLast() {
Tout ret; Tout ret;
mutex_l.lock(); mutex_last.lock();
ret = last; ret = last;
mutex_l.unlock(); mutex_last.unlock();
return ret; return ret;
} }
uint maxQueSize() { uint maxQueSize() {
uint ret; return max_size;
mutex.lock();
ret = max_size;
mutex.unlock();
return ret;
} }
void setMaxQueSize(uint count) { void setMaxQueSize(uint count) {
@@ -127,39 +134,35 @@ protected:
private: private:
void begin() {cnt = 0;} void begin() {cnt = 0;}
void run() { void run() {
//piCoutObj << "run ...";
mutex.lock(); mutex.lock();
if (in.isEmpty()) { while (in.isEmpty()) {
cv.wait(mutex);
if (terminating) {
mutex.unlock(); mutex.unlock();
piMSleep(10);
//piCoutObj << "run in empty";
return; return;
} }
if (next_overload && wait_next_pipe) { }
mutex.unlock(); mutex_wait.lock();
//piCoutObj << "wait" << &next_overload;
calculated(last, &next_overload);
piMSleep(10);
} else {
Tin t = in.dequeue(); Tin t = in.dequeue();
mutex.unlock(); mutex.unlock();
cv_wait.notifyAll();
mutex_wait.unlock();
bool ok = true; bool ok = true;
Tout r = calc(t, ok); Tout r = calc(t, ok);
if (ok) { if (ok) {
mutex_l.lock(); mutex_last.lock();
last = r; last = r;
mutex_l.unlock(); mutex_last.unlock();
cnt++; cnt++;
//piCoutObj << "calc ok" << &next_overload; //piCoutObj << "calc ok";
calculated(r, &next_overload); calculated(r, wait_next_pipe);
}
} }
//piCoutObj << "run ok"; //piCoutObj << "run ok";
} }
PIMutex mutex; PIMutex mutex, mutex_wait;
PIMutex mutex_l; PIConditionVariable cv, cv_wait;
PIMutex mutex_last;
bool wait_next_pipe; bool wait_next_pipe;
bool next_overload;
ullong cnt; ullong cnt;
PIQueue<Tin> in; PIQueue<Tin> in;
Tout last; Tout last;

View File

@@ -63,7 +63,7 @@ event started();
while (isRunning()) { while (isRunning()) {
run(); run();
ThreadFunc(); ThreadFunc();
msleep(timer_delay); piMSleep(timer_delay);
} }
event stopped(); event stopped();
end(); end();
@@ -329,13 +329,13 @@ bool PIThread::_startThread(void * func) {
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
if (ret == 0) { if (ret == 0) {
# ifdef MAC_OS # ifdef MAC_OS
pthread_setname_np(((PIString&)name().elided(15, 0.4f).resize(15, '\0')).dataAscii()); pthread_setname_np(((PIString&)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
pthread_threadid_np(PRIVATE->thread, (__uint64_t*)&tid_); pthread_threadid_np(PRIVATE->thread, (__uint64_t*)&tid_);
# else # else
# ifdef FREERTOS # ifdef FREERTOS
tid_ = PRIVATE->thread; tid_ = PRIVATE->thread;
# else # else
pthread_setname_np(PRIVATE->thread, ((PIString&)name().elided(15, 0.4f).resize(15, '\0')).dataAscii()); pthread_setname_np(PRIVATE->thread, ((PIString&)name().elided(15, 0.4f).resize(15, PIChar('\0'))).dataAscii());
# endif # endif
# endif # endif
#else #else
@@ -402,7 +402,7 @@ bool PIThread::waitForFinish(int timeout_msecs) {
if (!running_) return true; if (!running_) return true;
if (timeout_msecs < 0) { if (timeout_msecs < 0) {
while (running_) { while (running_) {
msleep(PIP_MIN_MSLEEP); piMinSleep();
#ifdef WINDOWS #ifdef WINDOWS
if (!isExists(PRIVATE->thread)) { if (!isExists(PRIVATE->thread)) {
unlock(); unlock();
@@ -414,7 +414,7 @@ bool PIThread::waitForFinish(int timeout_msecs) {
} }
tmf_.reset(); tmf_.reset();
while (running_ && tmf_.elapsed_m() < timeout_msecs) { while (running_ && tmf_.elapsed_m() < timeout_msecs) {
msleep(PIP_MIN_MSLEEP); piMinSleep();
#ifdef WINDOWS #ifdef WINDOWS
if (!isExists(PRIVATE->thread)) { if (!isExists(PRIVATE->thread)) {
unlock(); unlock();
@@ -430,12 +430,12 @@ bool PIThread::waitForStart(int timeout_msecs) {
if (running_) return true; if (running_) return true;
if (timeout_msecs < 0) { if (timeout_msecs < 0) {
while (!running_) while (!running_)
msleep(PIP_MIN_MSLEEP); piMinSleep();
return true; return true;
} }
tms_.reset(); tms_.reset();
while (!running_ && tms_.elapsed_m() < timeout_msecs) while (!running_ && tms_.elapsed_m() < timeout_msecs)
msleep(PIP_MIN_MSLEEP); piMinSleep();
return tms_.elapsed_m() < timeout_msecs; return tms_.elapsed_m() < timeout_msecs;
} }
@@ -456,9 +456,9 @@ void PIThread::_beginThread() {
PIINTROSPECTION_THREAD_START(this); PIINTROSPECTION_THREAD_START(this);
REGISTER_THREAD(this); REGISTER_THREAD(this);
running_ = true; running_ = true;
if (lockRun) mutex_.lock(); if (lockRun) thread_mutex.lock();
begin(); begin();
if (lockRun) mutex_.unlock(); if (lockRun) thread_mutex.unlock();
started(); started();
} }
@@ -466,7 +466,7 @@ void PIThread::_beginThread() {
void PIThread::_runThread() { void PIThread::_runThread() {
PIINTROSPECTION_THREAD_RUN(this); PIINTROSPECTION_THREAD_RUN(this);
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "..."; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "...";
if (lockRun) mutex_.lock(); if (lockRun) thread_mutex.lock();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok"; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "lock" << "ok";
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "..."; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "run" << "...";
#ifdef PIP_INTROSPECTION #ifdef PIP_INTROSPECTION
@@ -482,7 +482,7 @@ void PIThread::_runThread() {
if (ret_func != 0) ret_func(data_); if (ret_func != 0) ret_func(data_);
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "ok"; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "ret_func" << "ok";
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "..."; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "...";
if (lockRun) mutex_.unlock(); if (lockRun) thread_mutex.unlock();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "ok"; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "unlock" << "ok";
} }
@@ -491,11 +491,11 @@ void PIThread::_endThread() {
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "..."; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "...";
stopped(); stopped();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok"; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
if (lockRun) mutex_.lock(); if (lockRun) thread_mutex.lock();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "end" << "..."; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "end" << "...";
end(); end();
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok"; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "stop" << "ok";
if (lockRun) mutex_.unlock(); if (lockRun) thread_mutex.unlock();
terminating = running_ = false; terminating = running_ = false;
tid_ = -1; tid_ = -1;
//PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit"; //PICout(PICoutManipulators::DefaultControls) << "thread" << this << "exit";
@@ -554,7 +554,7 @@ void PIThread::__thread_func_once__() {
void PIThread::runOnce(PIObject * object, const char * handler, const PIString & name) { void PIThread::runOnce(PIObject * object, const char * handler, const PIString & name) {
PIThread * t = new PIThread(); PIThread * t = new PIThread();
t->setName(name); t->setName(name);
if (!PIObject::piConnectU(t, PIStringAscii("started"), object, object, PIStringAscii(handler), "PIThread::runOnce")) { if (!PIObject::piConnectU(t, PIStringAscii("started"), object, object, PIStringAscii(handler), "PIThread::runOnce").isValid()) {
delete t; delete t;
return; return;
} }

View File

@@ -131,11 +131,15 @@ public:
//! @brief Set necessity of lock every \a run with internal mutex //! @brief Set necessity of lock every \a run with internal mutex
void needLockRun(bool need) {lockRun = need;} void needLockRun(bool need) {lockRun = need;}
EVENT_HANDLER0(void, lock) {mutex_.lock();}
EVENT_HANDLER0(void, unlock) {mutex_.unlock();} //! @brief Lock internal mutex
EVENT_HANDLER0(void, lock) const {thread_mutex.lock();}
//! @brief Unlock internal mutex
EVENT_HANDLER0(void, unlock) const {thread_mutex.unlock();}
//! @brief Returns internal mutex //! @brief Returns internal mutex
PIMutex & mutex() {return mutex_;} PIMutex & mutex() const {return thread_mutex;}
//! @brief Returns thread ID //! @brief Returns thread ID
llong tid() const {return tid_;} llong tid() const {return tid_;}
@@ -239,7 +243,7 @@ protected:
int delay_, policy_; int delay_, policy_;
llong tid_; llong tid_;
void * data_; void * data_;
mutable PIMutex mutex_; mutable PIMutex thread_mutex;
PITimeMeasurer tmf_, tms_, tmr_; PITimeMeasurer tmf_, tms_, tmr_;
PIThread::Priority priority_; PIThread::Priority priority_;
ThreadFunc ret_func; ThreadFunc ret_func;

View File

@@ -26,7 +26,9 @@
#include "pitimer.h" #include "pitimer.h"
#include "pipipelinethread.h" #include "pipipelinethread.h"
#include "pigrabberbase.h" #include "pigrabberbase.h"
#include "pithreadpoolexecutor.h"
#include "piconditionvar.h" #include "piconditionvar.h"
#include "pithreadpoolexecutor.h"
#include "pithreadpoolloop.h"
#include "pithreadnotifier.h"
#endif // PITHREADMODULE_H #endif // PITHREADMODULE_H

View File

@@ -0,0 +1,39 @@
/*
PIP - Platform Independent Primitives
Class for simply notify and wait in different threads
Andrey Bychkov work.a.b@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/>.
*/
#include "pithreadnotifier.h"
PIThreadNotifier::PIThreadNotifier() : cnt(0) {}
void PIThreadNotifier::wait() {
m.lock();
while (cnt == 0) v.wait(m);
cnt--;
m.unlock();
}
void PIThreadNotifier::notifyOnce() {
m.lock();
cnt++;
v.notifyAll();
m.unlock();
}

View File

@@ -0,0 +1,52 @@
/*! @file pithreadnotifier.h
* @brief Class for simply notify and wait in different threads
*/
/*
PIP - Platform Independent Primitives
Class for simply notify and wait in different threads
Andrey Bychkov work.a.b@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 PITHREADNOTIFIER_H
#define PITHREADNOTIFIER_H
#include "piconditionvar.h"
class PIP_EXPORT PIThreadNotifier {
public:
PIThreadNotifier();
//! Start waiting, return if other thread call \a notifyOnce().
//! If \a notifyOnce() has been called before, then returns immediately.
//! If notifyOnce() has been called "n" times, then returns immediately "n" times,
//! but only if wait in one thread.
//! If many threads waiting, then If notifyOnce() has been called "n" times,
//! All threads total returns "n" times in random sequence.
void wait();
//! Notify one waiting thread, wich waiting on \a wait() function.
//! If many threads waiting, then notify randomly one.
//! If call this "n" times, then notify any waiting threads totally "n" times.
void notifyOnce();
private:
ullong cnt;
PIMutex m;
PIConditionVariable v;
};
#endif // PITHREADNOTIFIER_H

View File

@@ -0,0 +1,130 @@
/*
PIP - Platform Independent Primitives
Thread pool loop
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/>.
*/
#include "pithreadpoolloop.h"
#include "pisysteminfo.h"
#include "pithread.h"
/*! \class PIThreadPoolLoop
* @brief Thread class
* \details This class allow you parallelize loop.
*
* \section PIThreadPoolLoop_sec0 Usage
* This class designed to replace "for(;;)" statement in very simple way.
* In constructor several threads created, then by "setFunction()" method
* you should pass body of your loop, and then call "start()" or "exec()".
* Every thread take loop counter and execute your function until all
* counter range is passed.
*
* Example:
\code{.cpp}
PIVector<int> data(10, [](int i)->int{return i;});
piCout << data; // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
PIThreadPoolLoop pool;
pool.exec(0, data.size(), [&](int i){ // parallel analogue "for (int i = 0; i < data.size(); i++)"
data[i] = data[i] + 10;
});
piCout << data; // {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
\endcode
*
* Equivalent to:
\code{.cpp}
PIVector<int> data(10, [](int i)->int{return i;});
piCout << data; // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
pool.setFunction([&](int i){
data[i] = data[i] + 10;
});
pool.exec(0, data.size());
piCout << data; // {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
\endcode
*
* \section PIThreadPoolLoop_sec1 Important
* Due to multithreading it`s very important to protect output data of loop body, use mutex.
* Also remember that execution order is undefined and you shouldn`t use global variables in
* your function. Use local variables and lambda capture.
*
*/
PIThreadPoolLoop::PIThreadPoolLoop(int thread_cnt) {
if (thread_cnt <= 0)
thread_cnt = piMaxi(1, PISystemInfo::instance()->processorsCount);
piForTimes (thread_cnt) {
auto * t = new PIThread();
threads << t;
}
//piCout << "PIThreadPoolLoop" << proc_cnt << "threads";
}
PIThreadPoolLoop::~PIThreadPoolLoop() {
for (auto * t: threads) {
t->stop(false);
if (!t->waitForFinish(100))
t->terminate();
delete t;
}
}
void PIThreadPoolLoop::setFunction(std::function<void (int)> f) {
func = f;
}
void PIThreadPoolLoop::start(int index_start, int index_count) {
counter = index_start;
int end = index_start + index_count;
for (auto * t: threads)
t->start([this,end,t](){
while (1) {
int cc = counter.fetch_add(1);
if (cc >= end) {
t->stop(false);
return;
}
func(cc);
}
});
}
void PIThreadPoolLoop::exec(int index_start, int index_count) {
start(index_start, index_count);
wait();
}
void PIThreadPoolLoop::exec(int index_start, int index_count, std::function<void (int)> f) {
setFunction(f);
exec(index_start, index_count);
}
void PIThreadPoolLoop::wait() {
for (auto * t: threads)
t->waitForFinish();
}

View File

@@ -0,0 +1,69 @@
/*! @file pithreadpoolloop.h
* @brief Thread pool loop
*
* This file declare thread class and some wait functions
*/
/*
PIP - Platform Independent Primitives
Thread pool loop
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 PITHREADPOOLLOOP_H
#define PITHREADPOOLLOOP_H
#include "pivector.h"
class PIThread;
class PIP_EXPORT PIThreadPoolLoop {
public:
//! Contructs thread pool with threads count "thread_cnt".
//! If "thread_cnt" = -1 then system processors count used
PIThreadPoolLoop(int thread_cnt = -1);
virtual ~PIThreadPoolLoop();
//! Set threads function to "f" with format [](int){...}
void setFunction(std::function<void(int)> f);
//! Wait for all threads stop
void wait();
//! Start functions execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
void start(int index_start, int index_count);
//! Start functions execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! and wait for finish
void exec(int index_start, int index_count);
//! Start functions "f" execution with integer argument range
//! from "index_start" to "index_start + index_count - 1"
//! and wait for finish
void exec(int index_start, int index_count, std::function<void(int)> f);
private:
PIVector<PIThread * > threads;
std::function<void(int)> func;
std::atomic_int counter;
};
#endif

View File

@@ -648,11 +648,11 @@ bool PITimer::stop(bool wait) {
bool PITimer::waitForFinish(int timeout_msecs) { bool PITimer::waitForFinish(int timeout_msecs) {
if (timeout_msecs < 0) { if (timeout_msecs < 0) {
while (isRunning()) while (isRunning())
msleep(PIP_MIN_MSLEEP); piMinSleep();
return true; return true;
} }
PITimeMeasurer tm; PITimeMeasurer tm;
while (isRunning() && tm.elapsed_m() < timeout_msecs) while (isRunning() && tm.elapsed_m() < timeout_msecs)
msleep(PIP_MIN_MSLEEP); piMinSleep();
return tm.elapsed_m() < timeout_msecs; return tm.elapsed_m() < timeout_msecs;
} }

View File

@@ -2,63 +2,30 @@
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
PICLI cli(argc, argv); PIThreadNotifier n;
PITimer tm; int cnt1 = 0;
cli.addArgument("connect", true); int cnt2 = 0;
cli.addArgument("name", true); int cnt3 = 0;
PICloudClient c("127.0.0.1:10101"); PIThread t1([&n, &cnt1](){n.wait(); cnt1++; piMSleep(1);}, true);
// c.setReopenEnabled(true); PIThread t2([&n, &cnt2](){n.wait(); cnt2++; piMSleep(2);}, true);
PICloudServer s("127.0.0.1:10101"); piCout << "created";
PIVector<PICloudServer::Client *> clients; piMSleep(10);
CONNECTL(&tm, tickEvent, ([&](void *, int){ piCout << "unlock" << cnt1 << cnt2 << cnt3;
if (c.isConnected()) { n.notifyOnce(); cnt3++;
PIString str = "ping"; piMSleep(10);
piCout << "[Client] send:" << str; piCout << "unlock" << cnt1 << cnt2 << cnt3;
c.write(str.toByteArray()); n.notifyOnce(); cnt3++;
} piMSleep(10);
if (s.isRunning()) { piCout << "run" << cnt1 << cnt2 << cnt3;
for (auto cl : clients) { PIThread t3([&n, &cnt3](){n.notifyOnce(); cnt3++; piMSleep(1);}, true);
if (cl->isOpened()) { piMSleep(20);
PIString str = "ping_S"; t3.stop();
piCout << "[Server] send to" << cl << ":" << str; piMSleep(100);
cl->write(str.toByteArray()); piCout << "exit" << cnt1 << cnt2 << cnt3;
} PIByteArray ba = PIByteArray::fromHex("00aabbcc");
} PIByteArray ba2 = ba.getRange(1, 2);
} piCout << ba2.toHex();
})); // m.unlock();
CONNECTL(&c, threadedReadEvent, ([&](uchar * readed, int size){ // piMSleep(10);
PIByteArray ba(readed, size);
PIString str = PIString(ba);
piCout << "[Client] data:" << str;
if (str == "ping_S") c.write(PIString("pong_S").toByteArray());
}));
CONNECTL(&s, newConnection, ([&](PICloudServer::Client * cl){
piCout << "[Server] new client:" << cl;
clients << cl;
CONNECTL(cl, threadedReadEvent, ([&c, &s, cl](uchar * readed, int size){
PIByteArray ba(readed, size);
PIString str = PIString(ba);
piCout << "[Server] data from" << cl << ":" << str;
if (str == "ping") cl->write(PIString("pong").toByteArray());
}));
CONNECTL(cl, closed, ([&clients, cl](){
cl->stop();
clients.removeAll(cl);
cl->deleteLater();
}));
cl->startThreadedRead();
}));
if (cli.hasArgument("name")) s.setServerName(cli.argumentValue("name"));
if (cli.hasArgument("connect")) {
c.setServerName(cli.argumentValue("connect"));
c.startThreadedRead();
} else {
s.startThreadedRead();
}
tm.start(1000);
PIKbdListener ls;
ls.enableExitCapture(PIKbdListener::F10);
ls.start();
WAIT_FOR_EXIT
return 0; return 0;
} }

73
main_picloud_test.cpp Normal file
View File

@@ -0,0 +1,73 @@
#include "pip.h"
int main(int argc, char * argv[]) {
PIByteArray rnd;
rnd.resize(1024*1024, 'x');
PICLI cli(argc, argv);
PITimer tm;
cli.addArgument("connect", true);
cli.addArgument("name", true);
PICloudClient c("127.0.0.1:10101");
// c.setReopenEnabled(true);
PICloudServer s("127.0.0.1:10101");
PIVector<PICloudServer::Client *> clients;
CONNECTL(&tm, tickEvent, ([&](void *, int){
if (c.isConnected()) {
PIString str = "ping";
piCout << "[Client] send:" << str;
c.write(str.toByteArray());
}
if (s.isRunning()) {
for (auto cl : clients) {
if (cl->isOpened()) {
PIString str = "ping_S";
piCout << "[Server] send to" << cl << ":" << str;
cl->write(str.toByteArray());
}
}
}
}));
CONNECTL(&c, threadedReadEvent, ([&](uchar * readed, int size){
PIByteArray ba(readed, size);
if (size < 1024) {
PIString str = PIString(ba);
piCout << "[Client] data:" << str;
if (str == "ping_S") c.write(PIString("pong_S").toByteArray());
} else piCout << "[Client] blob:" << size;
}));
CONNECTL(&c, connected, ([](){piCout << "connected";}));
CONNECTL(&c, disconnected, ([](){piCout << "disconnected";}));
CONNECTL(&s, newConnection, ([&](PICloudServer::Client * cl){
piCout << "[Server] new client:" << cl;
clients << cl;
CONNECTL(cl, threadedReadEvent, ([&c, &s, cl, &rnd](uchar * readed, int size){
PIByteArray ba(readed, size);
PIString str = PIString(ba);
piCout << "[Server] data from" << cl << ":" << str;
if (str == "ping") {
cl->write(PIString("pong").toByteArray());
cl->write(rnd);
}
}));
CONNECTL(cl, closed, ([&clients, cl](){
cl->stop();
clients.removeAll(cl);
cl->deleteLater();
}));
cl->startThreadedRead();
}));
if (cli.hasArgument("name")) s.setServerName(cli.argumentValue("name"));
if (cli.hasArgument("connect")) {
c.setServerName(cli.argumentValue("connect"));
c.startThreadedRead();
} else {
s.startThreadedRead();
}
tm.start(1000);
PIKbdListener ls;
ls.enableExitCapture(PIKbdListener::F10);
ls.start();
WAIT_FOR_EXIT
return 0;
}

View File

@@ -25,3 +25,4 @@ endmacro()
pip_test(concurrent "") pip_test(concurrent "")
pip_test(math "") pip_test(math "")
pip_test(core "") pip_test(core "")
pip_test(piobject "")

View File

@@ -88,7 +88,7 @@ TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) {
// Missing unlock // Missing unlock
}); });
variable->notifyOne(); variable->notifyOne();
msleep(WAIT_THREAD_TIME_MS); piMSleep(WAIT_THREAD_TIME_MS);
ASSERT_FALSE(m.tryLock()); ASSERT_FALSE(m.tryLock());
} }
@@ -130,7 +130,7 @@ TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) {
isConditionChecked = false; isConditionChecked = false;
m.unlock(); m.unlock();
variable->notifyOne(); variable->notifyOne();
msleep(threadStartTime + 1); piMSleep(threadStartTime + 1);
m.lock(); m.lock();
ASSERT_TRUE(isConditionChecked); ASSERT_TRUE(isConditionChecked);
m.unlock(); m.unlock();
@@ -198,6 +198,6 @@ TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) {
condition = true; condition = true;
m.unlock(); m.unlock();
variable->notifyOne(); variable->notifyOne();
msleep(WAIT_THREAD_TIME_MS); piMSleep(WAIT_THREAD_TIME_MS);
ASSERT_FALSE(thread->isRunning()); ASSERT_FALSE(thread->isRunning());
} }

View File

@@ -0,0 +1,34 @@
#include "gtest/gtest.h"
#include "pithreadnotifier.h"
TEST(PIThreadNotifierTest, One) {
PIThreadNotifier n;
int cnt = 0;
PIThread t1([&n, &cnt](){n.wait(); cnt++;}, true);
piMSleep(10);
n.notifyOnce();
piMSleep(10);
ASSERT_EQ(cnt, 1);
n.notifyOnce();
piMSleep(10);
ASSERT_EQ(cnt, 2);
}
TEST(PIThreadNotifierTest, Two) {
PIThreadNotifier n;
int cnt1 = 0;
int cnt2 = 0;
int cnt3 = 0;
PIThread t1([&n, &cnt1](){n.wait(); cnt1++; piMSleep(2);}, true);
PIThread t2([&n, &cnt2](){n.wait(); cnt2++; piMSleep(2);}, true);
PIThread t3([&n, &cnt3](){n.notifyOnce(); cnt3++; piMSleep(1);}, true);
piMSleep(20);
t3.stop(true);
piMSleep(100);
t1.stop();
t2.stop();
ASSERT_EQ(cnt1+cnt2, cnt3);
}

View File

@@ -1,54 +1,73 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "pimathmatrix.h" #include "pimathmatrix.h"
bool cmpSquareMatrixWithValue(PIMathMatrix<double> matrix, double val, int num) { template<typename Type>
bool b = true; bool cmpSquareMatrixWithValue(PIMathMatrix<Type> matrix, Type val, int num) {
for(int i = 0; i < num; i++) { for(int i = 0; i < num; i++) {
for(int j = 0; j < num; j++) { for(int j = 0; j < num; j++) {
if(matrix.element(i, j) != val) { if(matrix.element(i, j) != val) {
b = false; return false;
} }
} }
} }
return b; return true;
} }
TEST(PIMathMatrix_Test, identity) { TEST(PIMathMatrix_Test, constructor1) {
PIMathMatrix<double> matrix(3, 3, 5.0);
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix, 5.0, 3));
}
TEST(PIMathMatrix_Test, constructor2) {
PIVector<double> vector(2, 5.0);
PIMathMatrix<PIVector<double>> matrix(3, 3, vector);
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix, vector, 3));
}
TEST(PIMathMatrix_Test, constructor3) {
PIVector2D<double> vector(2, 2, 5.0);
PIMathMatrix<double> matrix(vector);
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix, 5.0, 2));
}
TEST(PIMathMatrix_Test, identity1) {
auto matrix = PIMathMatrix<double>::identity(3, 3); auto matrix = PIMathMatrix<double>::identity(3, 3);
for(int i = 0; i < 3; i++) { for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) { for(int j = 0; j < 3; j++) {
if(i != j) { if(i != j) {
if(matrix[i][j] != 0.0){ if(matrix[i][j] != 0.0){
ASSERT_TRUE(false); FAIL();
} }
} }
else { else {
if(matrix[i][i] != 1.0){ if(matrix[i][i] != 1.0){
ASSERT_TRUE(false); FAIL();
} }
} }
} }
} }
ASSERT_TRUE(true); SUCCEED();
}
TEST(PIMathMatrix_Test, identity2) {
auto matrix = PIMathMatrix<double>::identity(4, 3);
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 4; j++) {
if(matrix.element(i,j) != (i == j ? 1. : 0.))
FAIL();
}
}
} }
TEST(PIMathMatrixT_Test, element) { TEST(PIMathMatrixT_Test, element) {
auto matrix = PIMathMatrix<double>::identity(3, 3); auto matrix = PIMathMatrix<double>::identity(3, 3);
for(int i = 0; i < 3; i++){ for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++){ for(int j = 0; j < 3; j++) {
if(i != j){ if(matrix.element(i,j) != (i == j ? 1. : 0.))
if(matrix[i][j] != 0.0){ FAIL();
ASSERT_TRUE(false);
} }
} }
else { SUCCEED();
if(matrix.element(i,i) != 1.0) {
ASSERT_TRUE(false);
}
}
}
}
ASSERT_TRUE(true);
} }
TEST(PIMathMatrix_Test, matrixRow) { TEST(PIMathMatrix_Test, matrixRow) {
@@ -57,10 +76,10 @@ TEST(PIMathMatrix_Test, matrixRow) {
auto matrix = PIMathMatrix<double>::matrixRow(vector); auto matrix = PIMathMatrix<double>::matrixRow(vector);
for(uint i = 0; i < vector.size(); i++) { for(uint i = 0; i < vector.size(); i++) {
if(matrix[0][i] != 3.0) { if(matrix[0][i] != 3.0) {
ASSERT_TRUE(false); FAIL();
} }
} }
ASSERT_TRUE(true); SUCCEED();
} }
TEST(PIMathMatrix_Test, matrixCol) { TEST(PIMathMatrix_Test, matrixCol) {
@@ -69,10 +88,10 @@ TEST(PIMathMatrix_Test, matrixCol) {
auto matrix = PIMathMatrix<double>::matrixCol(vector); auto matrix = PIMathMatrix<double>::matrixCol(vector);
for(uint i = 0; i < vector.size(); i++) { for(uint i = 0; i < vector.size(); i++) {
if(matrix[i][0] != 3.0) { if(matrix[i][0] != 3.0) {
ASSERT_TRUE(false); FAIL();
} }
} }
ASSERT_TRUE(true); SUCCEED();
} }
TEST(PIMathMatrix_Test, setCol) { TEST(PIMathMatrix_Test, setCol) {
@@ -83,10 +102,10 @@ TEST(PIMathMatrix_Test, setCol) {
matrix.setCol(0, vector); matrix.setCol(0, vector);
for(uint i = 0; i < vector.size(); i++) { for(uint i = 0; i < vector.size(); i++) {
if(matrix[i][0] != 10.0) { if(matrix[i][0] != 10.0) {
ASSERT_TRUE(false); FAIL();
} }
} }
ASSERT_TRUE(true); SUCCEED();
} }
TEST(PIMathMatrix_Test, setRow) { TEST(PIMathMatrix_Test, setRow) {
@@ -97,10 +116,10 @@ TEST(PIMathMatrix_Test, setRow) {
matrix.setRow(0, vector); matrix.setRow(0, vector);
for(uint i = 0; i < vector.size(); i++) { for(uint i = 0; i < vector.size(); i++) {
if(matrix[0][i] != 10.0) { if(matrix[0][i] != 10.0) {
ASSERT_TRUE(false); FAIL();
} }
} }
ASSERT_TRUE(true); SUCCEED();
} }
TEST(PIMathMatrix_Test, swapCols) { TEST(PIMathMatrix_Test, swapCols) {
@@ -137,407 +156,3 @@ TEST(PIMathMatrix_Test, swapCols) {
} }
ASSERT_TRUE((memcmp(a1, b2, sizeof(b1)) == 0) && (memcmp(a2, b1, sizeof(b1)) == 0) && (memcmp(a3, b3, sizeof(b1)) == 0)); ASSERT_TRUE((memcmp(a1, b2, sizeof(b1)) == 0) && (memcmp(a2, b1, sizeof(b1)) == 0) && (memcmp(a3, b3, sizeof(b1)) == 0));
} }
TEST(PIMathMatrix_Test, swapRows) {
PIMathMatrix<double> origMatr;
PIMathMatrix<double> matrix1;
PIMathVector<double> vector;
uint i1 = 0; uint i2 = 1;
double a1[3], a2[3], a3[3];
double b1[3], b2[3], b3[3];
vector.resize(3, 3.0);
vector[0] = 3.0;
vector[1] = 6.0;
vector[2] = 8.0;
matrix1 = origMatr.identity(3, 3);
matrix1.setCol(0, vector);
vector[0] = 2.0;
vector[1] = 1.0;
vector[2] = 4.0;
matrix1.setCol(1, vector);
vector[0] = 6.0;
vector[1] = 2.0;
vector[2] = 5.0;
matrix1.setCol(2, vector);
for(int i = 0; i < 3; i++) {
a1[i] = matrix1.element(0, i);
a2[i] = matrix1.element(1, i);
a3[i] = matrix1.element(2, i);
}
matrix1.swapRows(i1, i2);
for(int i = 0; i < 3; i++) {
b1[i] = matrix1.element(0, i);
b2[i] = matrix1.element(1, i);
b3[i] = matrix1.element(2, i);
}
ASSERT_TRUE((memcmp(a1, b2, sizeof(b1)) == 0) && (memcmp(a2, b1, sizeof(b1)) == 0) && (memcmp(a3, b3, sizeof(b1)) == 0));
}
TEST(PIMathMatrix_Test, fill) {
PIMathMatrix<double> matrix(3, 3, 5.0);
matrix.fill(7.0);
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix, 7.0, 3));
}
TEST(PIMathMatrix_Test, isSquareTrue) {
PIMathMatrix<double> matrix(3, 3, 1.0);
ASSERT_TRUE(matrix.isSquare());
}
TEST(PIMathMatrix_Test, isSquareFalse) {
PIMathMatrix<double> matrix(2, 4, 1.0);
ASSERT_FALSE(matrix.isSquare());
}
TEST(PIMathMatrix_Test, isIdentityTrue) {
auto matrix = PIMathMatrix<double>::identity(3, 3);
ASSERT_TRUE(matrix.isIdentity());
}
TEST(PIMathMatrix_Test, isIdentityFalse) {
PIMathMatrix<double> matrix(3, 3, 5.0);
ASSERT_FALSE(matrix.isIdentity());
}
TEST(PIMathMatrix_Test, isNullTrue) {
PIMathMatrix<double> matrix(3, 3, 0.0);
ASSERT_TRUE(matrix.isNull());
}
TEST(PIMathMatrix_Test, isNullFalse) {
PIMathMatrix<double> matrix(3, 3, 5.0);
ASSERT_FALSE(matrix.isNull());
}
TEST(PIMathMatrix_Test, isValidTrue) {
PIMathMatrix<double> matrix(3, 3, 1.62);
ASSERT_TRUE(matrix.isValid());
}
TEST(PIMathMatrix_Test, isValidFalse) {
PIMathMatrix<double> matrix;
ASSERT_FALSE(matrix.isValid());
}
TEST(PIMathMatrix_Test, operator_Assignment) {
PIMathMatrix<double> matrix1(3, 3, 5.72);
PIMathMatrix<double> matrix2(3, 3, 7.12);
matrix1 = matrix2;
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 7.12, 3));
}
TEST(PIMathMatrix_Test, operator_EqualTrue) {
PIMathMatrix<double> matrix1(2, 2, 2.0);
PIMathMatrix<double> matrix2(2, 2, 2.0);
matrix1.element(0, 0) = 5.1;
matrix1.element(0, 1) = 1.21;
matrix1.element(1, 1) = 0.671;
matrix1.element(1, 0) = 2.623;
matrix2.element(0, 0) = 5.1;
matrix2.element(0, 1) = 1.21;
matrix2.element(1, 1) = 0.671;
matrix2.element(1, 0) = 2.623;
ASSERT_TRUE(matrix1 == matrix2);
}
TEST(PIMathMatrix_Test, operator_EqualFalse) {
PIMathMatrix<double> matrix1(2, 2, 2.0);
PIMathMatrix<double> matrix2(2, 2, 2.0);
matrix1.element(0, 0) = 5.1;
matrix1.element(0, 1) = 1.21;
matrix1.element(1, 1) = 0.671;
matrix1.element(1, 0) = 2.623;
matrix2.element(0, 0) = 5.1;
matrix2.element(0, 1) = 1.21;
matrix2.element(1, 1) = 665.671;
matrix2.element(1, 0) = 2.623;
ASSERT_FALSE(matrix1 == matrix2);
}
TEST(PIMathMatrix_Test, operator_Not_EqualTrue) {
PIMathMatrix<double> matrix1(2, 2, 2.0);
PIMathMatrix<double> matrix2(2, 2, 2.0);
matrix1.element(0, 0) = 5.1;
matrix1.element(0, 1) = 1.21;
matrix1.element(1, 1) = 0.671;
matrix1.element(1, 0) = 2.623;
matrix2.element(0, 0) = 5.1;
matrix2.element(0, 1) = 1.21;
matrix2.element(1, 1) = 665.671;
matrix2.element(1, 0) = 2.623;
ASSERT_TRUE(matrix1 != matrix2);
}
TEST(PIMathMatrix_Test, operator_Not_EqualFalse) {
PIMathMatrix<double> matrix1(2, 2, 2.0);
PIMathMatrix<double> matrix2(2, 2, 2.0);
matrix1.element(0, 0) = 5.1;
matrix1.element(0, 1) = 1.21;
matrix1.element(1, 1) = 0.671;
matrix1.element(1, 0) = 2.623;
matrix2.element(0, 0) = 5.1;
matrix2.element(0, 1) = 1.21;
matrix2.element(1, 1) = 0.671;
matrix2.element(1, 0) = 2.623;
ASSERT_FALSE(matrix1 != matrix2);
}
TEST(PIMathMatrix_Test, operator_Addition_Aassignment) {
PIMathMatrix<double> matrix1(3, 3, 6.72);
PIMathMatrix<double> matrix2(3, 3, 1.0);
matrix1 += matrix2;
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 7.72, 3));
}
TEST(PIMathMatrix_Test, operator_Subtraction_Assignment) {
PIMathMatrix<double> matrix1(3, 3, 1.0);
PIMathMatrix<double> matrix2(3, 3, 6.72);
matrix1 -= matrix2;
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, -5.72, 3));
}
TEST(PIMathMatrix_Test, operator_Multiplication_Assignment) {
PIMathMatrix<double> matrix1(3, 3, 6.72);
matrix1 *= 2.0;
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 13.44, 3));
}
TEST(PIMathMatrix_Test, operator_Division_Assignment) {
PIMathMatrix<double> matrix1(3, 3, 6.72);
matrix1 /= 2.0;
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1, 3.36, 3));
}
TEST(PIMathMatrix_Test, operator_Addition) {
PIMathMatrix<double> matrix1(3, 3, 6.72);
PIMathMatrix<double> matrix2(3, 3, 8.28);
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 + matrix2, 15.0, 3));
}
TEST(PIMathMatrix_Test, operator_Subtraction) {
PIMathMatrix<double> matrix1(3, 3, 6.0);
PIMathMatrix<double> matrix2(3, 3, 5.0);
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 - matrix2, 1.0, 3));
}
TEST(PIMathMatrix_Test, operator_Multiplication) {
PIMathMatrix<double> matrix1(3, 3, 6.72);
PIMathMatrix<double> matrix2(3, 3, 5.0);
matrix2 = matrix1*4.0;
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix2, 26.88, 3));
}
TEST(PIMathMatrix_Test, operator_Division) {
PIMathMatrix<double> matrix1(3, 3, 6.72);
PIMathMatrix<double> matrix2(3, 3, 5.0);
matrix2 = matrix1/4.0;
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix2, 1.68, 3));
}
TEST(PIMathMatrix_Test, determinantIfSquare) {
double d;
double i = 59.0;
PIMathMatrix<double> matrix(3, 3, 0.0);
PIMathVector<double> vector;
vector.resize(3, 3.0);
vector[0] = 3.0;
vector[1] = 6.0;
vector[2] = 8.0;
matrix.setCol(0, vector);
vector[0] = 2.0;
vector[1] = 1.0;
vector[2] = 4.0;
matrix.setCol(1, vector);
vector[0] = 6.0;
vector[1] = 2.0;
vector[2] = 5.0;
matrix.setCol(2, vector);
d = matrix.determinant();
ASSERT_DOUBLE_EQ(d, i);
}
TEST(PIMathMatrix_Test, trace) {
PIMathMatrix<double> matrix(3, 3, 0.0);
double t;
double i = 9.0;
PIMathVector<double> vector;
vector.resize(3, 3.0);
vector[0] = 3.0;
vector[1] = 6.0;
vector[2] = 8.0;
matrix.setCol(0, vector);
vector[0] = 2.0;
vector[1] = 1.0;
vector[2] = 4.0;
matrix.setCol(1, vector);
vector[0] = 6.0;
vector[1] = 2.0;
vector[2] = 5.0;
matrix.setCol(2, vector);
t = matrix.trace();
ASSERT_DOUBLE_EQ(t, i);
}
TEST(PIMathMatrix_Test, toUpperTriangular) {
PIMathMatrix<double> matrix(3, 3, 0.0);
double d1, d2 = 1;
int i;
PIMathVector<double> vector;
vector.resize(3, 3.0);
vector[0] = 3.0;
vector[1] = 6.0;
vector[2] = 8.0;
matrix.setCol(0, vector);
vector[0] = 2.0;
vector[1] = 1.0;
vector[2] = 4.0;
matrix.setCol(1, vector);
vector[0] = 6.0;
vector[1] = 2.0;
vector[2] = 5.0;
matrix.setCol(2, vector);
d1 = matrix.determinant();
matrix.toUpperTriangular();
for(i = 0; i < 3; i++)
{
d2 = d2 * matrix.element(i, i);
}
ASSERT_DOUBLE_EQ(d1, d2);
}
TEST(PIMathMatrix_Test, invert) {
double d1, d2;
PIMathMatrix<double> matrix1(3, 3, 0.0);
PIMathMatrix<double> matrix2(3, 3, 0.0);
PIMathMatrix<double> matrix3(3, 3, 0.0);
PIMathMatrix<double> matrix4(3, 3, 0.0);
PIMathVector<double> vector;
vector.resize(3, 3.0);
vector[0] = 3.0;
vector[1] = 6.0;
vector[2] = 8.0;
matrix1.setCol(0, vector);
vector[0] = 2.0;
vector[1] = 1.0;
vector[2] = 4.0;
matrix1.setCol(1, vector);
vector[0] = 6.0;
vector[1] = 2.0;
vector[2] = 5.0;
matrix1.setCol(2, vector);
d1 = matrix1.determinant();
matrix2 = matrix1;
matrix2.invert();
d2 = matrix2.determinant();
matrix4.invert();
ASSERT_TRUE((matrix3 == matrix4) && (round((1/d1)*10000)/10000 == round(d2*10000)/10000));
}
TEST(PIMathMatrix_Test, inverted) {
double d1, d2;
PIMathMatrix<double> matrix1(3, 3, 0.0);
PIMathMatrix<double> matrix2(3, 3, 0.0);
PIMathMatrix<double> matrix3(3, 3, 0.0);
PIMathMatrix<double> matrix4(3, 3, 0.0);
PIMathVector<double> vector;
vector.resize(3, 3.0);
vector[0] = 3.0;
vector[1] = 6.0;
vector[2] = 8.0;
matrix1.setCol(0, vector);
vector[0] = 2.0;
vector[1] = 1.0;
vector[2] = 4.0;
matrix1.setCol(1, vector);
vector[0] = 6.0;
vector[1] = 2.0;
vector[2] = 5.0;
matrix1.setCol(2, vector);
d1 = matrix1.determinant();
matrix2 = matrix1;
matrix1 = matrix2.invert();
d2 = matrix1.determinant();
matrix3 = matrix4.invert();
ASSERT_TRUE((matrix3 == matrix4) && (round((1/d1)*10000)/10000 == round(d2*10000)/10000));
}
TEST(PIMathMatrix_Test, transposed) {
PIMathMatrix<double> origMatr;
double d1, d2;
PIMathMatrix<double> matrix1;
PIMathMatrix<double> matrix2;
PIMathMatrix<double> matrix3;
PIMathVector<double> vector;
vector.resize(3, 3.0);
vector[0] = 3.0;
vector[1] = 6.0;
vector[2] = 8.0;
matrix1 = origMatr.identity(3, 3);
matrix1.setCol(0, vector);
vector[0] = 2.0;
vector[1] = 1.0;
vector[2] = 4.0;
matrix1.setCol(1, vector);
vector[0] = 6.0;
vector[1] = 2.0;
vector[2] = 5.0;
matrix1.setCol(2, vector);
d1 = matrix1.determinant();
matrix2 = matrix1.transposed();
d2 = matrix2.determinant();
matrix3 = matrix2.transposed();
ASSERT_TRUE((d1 == d2) && (matrix1 == matrix3));
}
TEST(PIMathMatrix_Test, matrixMultiplication) {
PIMathMatrix<double> matrix1(2, 2, 1.5);
PIMathMatrix<double> matrix2(2, 2, 2.5);
ASSERT_TRUE(cmpSquareMatrixWithValue(matrix1 * matrix2, 7.5, 2));
}
TEST(PIMathMatrix_Test, matrixAndVectorMultiplication) {
PIMathMatrix<double> matrix1(2, 2, 1.5);
PIMathVector<double> vector;
vector.resize(2, 2.5);
for(uint i = 0; i < 2; i++) {
if((matrix1 * vector)[i] != 7.5) {
ASSERT_TRUE(false);
}
}
ASSERT_TRUE(true);
}
TEST(PIMathMatrix_Test, vectorAndMatrixMultiplication) {
PIMathMatrix<double> matrix1(2, 2, 1.5);
PIMathVector<double> vector;
vector.resize(2, 2.5);
for(uint i = 0; i < 2; i++) {
if((vector * matrix1)[i] != 7.5) {
ASSERT_TRUE(false);
}
}
ASSERT_TRUE(true);
}
TEST(PIMathMatrix_Test, valAndMatrixMultiplication) {
PIMathMatrix<double> matrix1(3, 3, 1.5);
ASSERT_TRUE(cmpSquareMatrixWithValue(25.0*matrix1, 37.5, 3));
}
TEST(PIMathMatrix_Test, hermitian) {
complex<double> val;
complex<double> res;
val.imag(1.0);
val.real(1.0);
PIMathMatrix<complex<double>> matrix(3, 3, val);
res.imag(-1.0);
res.real(1.0);
auto matr = hermitian(matrix);
for(uint i = 0; i < 3; i++) {
for(uint j = 0; j < 3; j++) {
if(matr.element(i, j) != res) {
ASSERT_TRUE(false);
}
}
}
ASSERT_TRUE(true);
}

View File

@@ -5,15 +5,14 @@ const uint rows = 3;
const uint cols = 3; const uint cols = 3;
bool cmpSquareMatrixWithValue(PIMathMatrixT<rows, cols, double> matrix, double val, int num) { bool cmpSquareMatrixWithValue(PIMathMatrixT<rows, cols, double> matrix, double val, int num) {
bool b = true;
for(int i = 0; i < num; i++) { for(int i = 0; i < num; i++) {
for(int j = 0; j < num; j++) { for(int j = 0; j < num; j++) {
if(matrix.at(i, j) != val) { if(matrix.at(i, j) != val) {
b = false; return false;
} }
} }
} }
return b; return true;
} }
TEST(PIMathMatrixT_Test, identity) { TEST(PIMathMatrixT_Test, identity) {

317
tests/piobject/connect.cpp Normal file
View File

@@ -0,0 +1,317 @@
#include "gtest/gtest.h"
#include "piobject.h"
class Object : public PIObject
{
PIOBJECT(Object)
public:
Object() {
x=0;
// CONNECTL(this, deleted, [](PIObject * o){
// piCout << "deteted" << o;
// });
}
void test() {event_test();}
void test_val() {event_val(x);}
int getX() const {return x;}
EVENT(event_test)
EVENT1(event_val, int, arg)
EVENT_HANDLER(void, handler_test) {x++;}
EVENT_HANDLER1(void, handler_val, int, arg) {x = arg;}
private:
int x;
};
TEST(PiobjectConnections, CONNECT0) {
Object a;
Object b;
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
CONNECT0(void, &a, event_test, &b, handler_test);
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECT0_DISCONNECT) {
Object a;
Object b;
a.setName("A");
b.setName("B");
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
CONNECT0(void, &a, event_test, &b, handler_test);
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
PIObject::piDisconnect(&a, "event_test");
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECTU) {
Object a;
Object b;
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
CONNECTU(&a, event_test, &b, handler_test);
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECTU_DISCONNECT) {
Object a;
Object b;
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
CONNECTU(&a, event_test, &b, handler_test);
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
PIObject::piDisconnect(&a, "event_test");
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
a.handler_val(99);
ASSERT_EQ(a.getX(), 99);
ASSERT_EQ(b.getX(), 1);
CONNECTU(&a, event_val, &b, handler_val);
ASSERT_EQ(a.getX(), 99);
ASSERT_EQ(b.getX(), 1);
a.test_val();
ASSERT_EQ(a.getX(), 99);
ASSERT_EQ(b.getX(), 99);
a.handler_val(-1);
ASSERT_EQ(a.getX(), -1);
ASSERT_EQ(b.getX(), 99);
PIObject::piDisconnect(&a, "event_val", &b);
ASSERT_EQ(a.getX(), -1);
ASSERT_EQ(b.getX(), 99);
a.test_val();
ASSERT_EQ(a.getX(), -1);
ASSERT_EQ(b.getX(), 99);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECTL) {
Object a;
Object b;
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
CONNECTL(&a, event_test, [&b](){
b.handler_val(7);
});
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 7);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 7);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECTL_DISCONNECT) {
Object a;
Object b;
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
CONNECTL(&a, event_test, [&b](){
b.handler_test();
});
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
b.handler_test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 2);
PIObject::piDisconnect(&a, "event_test");
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 2);
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 2);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECTL_twice) {
Object a;
Object b;
CONNECTL(&a, event_test, [&b](){
b.handler_test();
});
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
CONNECTL(&a, event_test, [&b](){
b.handler_test();
});
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 3);
b.handler_val(0);
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
PIObject::piDisconnect(&a, "event_test");
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 0);
CONNECTL(&a, event_test, [&b](){
b.handler_test();
});
a.test();
ASSERT_EQ(a.getX(), 0);
ASSERT_EQ(b.getX(), 1);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECT_AFTER_DISCONNECT) {
Object a;
Object b;
CONNECTL(&a, event_test, [&b](){
b.handler_test();
});
a.test();
ASSERT_EQ(b.getX(), 1);
PIObject::piDisconnect(&a, "event_test");
a.test();
ASSERT_EQ(b.getX(), 1);
DISCONNECT1(void, int, &a, event_val, &b, handler_val);
CONNECT1(void, int, &a, event_val, &b, handler_val);
a.handler_val(8);
a.test_val();
ASSERT_EQ(a.getX(), 8);
ASSERT_EQ(b.getX(), 8);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECTL_WRONG_DISCONNECT) {
Object a;
Object b;
CONNECTL(&a, event_test, [&b](){
b.handler_test();
});
a.test();
ASSERT_EQ(b.getX(), 1);
PIObject::piDisconnect(&b, "event_test");
a.test();
ASSERT_EQ(b.getX(), 2);
PIObject::piDisconnect(&a, "event_test");
a.test();
ASSERT_EQ(b.getX(), 2);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECT_WRONG_DISCONNECT) {
Object a;
Object b;
CONNECT0(void, &a, event_test, &b, handler_test);
a.test();
ASSERT_EQ(b.getX(), 1);
PIObject::piDisconnect(&b, "event_test");
a.test();
ASSERT_EQ(b.getX(), 2);
PIObject::piDisconnect(&a, "event_test");
a.test();
ASSERT_EQ(b.getX(), 2);
// piCout << "================";
}
TEST(PiobjectConnections, CONNECTU_WRONG_DISCONNECT) {
Object a;
Object b;
CONNECTU(&a, event_test, &b, handler_test);
a.test();
ASSERT_EQ(b.getX(), 1);
PIObject::piDisconnect(&b, "event_test");
a.test();
ASSERT_EQ(b.getX(), 2);
PIObject::piDisconnect(&a, "event_test");
a.test();
ASSERT_EQ(b.getX(), 2);
// piCout << "================";
}

View File

@@ -0,0 +1,51 @@
#include "gtest/gtest.h"
#include "piobject.h"
std::atomic<int> obj_cnt;
class Send: public PIObject {
PIOBJECT(Send)
public:
Send() {obj_cnt++;}
~Send() {obj_cnt--;}
EVENT1(ev, PIObject * , o)
};
class Recv: public PIObject {
PIOBJECT(Recv)
public:
Recv() {obj_cnt++;}
~Recv() {obj_cnt--;}
EVENT_HANDLER1(void, eh, PIObject * , o) {
o->deleteLater();
piMSleep(10);
}
};
TEST(Piobject, deleteLater) {
obj_cnt = 0;
Send * s = new Send();
Recv * r = new Recv();
CONNECTU(s, ev, r, eh);
s->ev(r);
r->deleteLater();
s->deleteLater();
piMSleep(100);
ASSERT_EQ(obj_cnt, 0);
PIVector<Send *> s2;
s2.resize(100, new Send());
for (auto o : s2) o->deleteLater();
piMSleep(10);
ASSERT_EQ(obj_cnt, 0);
s2.clear();
PIVector<Recv *> r2;
r2.resize(100, [](size_t i){return new Recv();});
for (auto o : r2) o->deleteLater();
piMSleep(10);
ASSERT_EQ(obj_cnt, 0);
r2.clear();
}

View File

@@ -22,5 +22,6 @@ if (NOT DEFINED ANDROID_PLATFORM)
DEPLOY_DIR ${CMAKE_CURRENT_BINARY_DIR} DEPLOY_DIR ${CMAKE_CURRENT_BINARY_DIR}
DESTINATION ${ROOT_DIR}/release DESTINATION ${ROOT_DIR}/release
DEB_ADD_SERVICE DEB_ADD_SERVICE
ADD_MANIFEST
) )
endif() endif()

View File

@@ -4,9 +4,12 @@ CloudServer::CloudServer(DispatcherClient * c, const PIByteArray & sname) : serv
setName(sname.toHex()); setName(sname.toHex());
server_uuid = sname; server_uuid = sname;
CONNECTL(c, dataReadedServer, ([this](uint id, PIByteArray & ba){ CONNECTL(c, dataReadedServer, ([this](uint id, PIByteArray & ba){
last_ping.reset();
DispatcherClient * cl = index_clients.value(id, nullptr); DispatcherClient * cl = index_clients.value(id, nullptr);
if (cl) cl->sendData(ba); if (cl) cl->sendData(ba);
})); }));
CONNECTL(c, pingReceived, [this]() {last_ping.reset();});
last_ping.reset();
} }
@@ -23,20 +26,21 @@ PIByteArray CloudServer::serverUUID() const {
void CloudServer::addClient(DispatcherClient * c) { void CloudServer::addClient(DispatcherClient * c) {
last_ping.reset();
clients << c; clients << c;
index_clients.insert(c->clientId(), c); uint cid = c->clientId();
index_clients.insert(cid, c);
c->sendConnected(1); c->sendConnected(1);
server->sendConnected(c->clientId()); server->sendConnected(cid);
CONNECTL(c, dataReaded, ([this, c](PIByteArray & ba){ CONNECTL(c, dataReaded, ([this, cid](PIByteArray & ba){
// piCoutObj << c->clientId() << "dataReaded"; // piCoutObj << c->clientId() << "dataReaded";
if (clients.contains(c)) { server->sendDataToClient(ba, cid);
server->sendDataToClient(ba, c->clientId());
}
})); }));
} }
void CloudServer::removeClient(DispatcherClient * c) { void CloudServer::removeClient(DispatcherClient * c) {
last_ping.reset();
clients.removeOne(c); clients.removeOne(c);
index_clients.removeOne(c->clientId()); index_clients.removeOne(c->clientId());
server->sendDisconnected(c->clientId()); server->sendDisconnected(c->clientId());
@@ -48,6 +52,11 @@ PIVector<DispatcherClient *> CloudServer::getClients() {
} }
double CloudServer::lastPing() {
return last_ping.elapsed_s();
}
void CloudServer::printStatus() { void CloudServer::printStatus() {
piCout << " " << "Clients for" << server->address() << server_uuid.toHex() << ":"; piCout << " " << "Clients for" << server->address() << server_uuid.toHex() << ":";
for (auto c: clients) { for (auto c: clients) {

View File

@@ -15,12 +15,14 @@ public:
PIVector<DispatcherClient*> getClients(); PIVector<DispatcherClient*> getClients();
EVENT_HANDLER0(void, printStatus); EVENT_HANDLER0(void, printStatus);
const DispatcherClient * getConnection() const {return server;} const DispatcherClient * getConnection() const {return server;}
double lastPing();
private: private:
DispatcherClient * server; DispatcherClient * server;
PIVector<DispatcherClient*> clients; PIVector<DispatcherClient*> clients;
PIMap<uint, DispatcherClient*> index_clients; PIMap<uint, DispatcherClient*> index_clients;
PIByteArray server_uuid; PIByteArray server_uuid;
PITimeMeasurer last_ping;
}; };
#endif // CLOUDSERVER_H #endif // CLOUDSERVER_H

View File

@@ -6,7 +6,7 @@ DispatcherClient::DispatcherClient(PIEthernet * eth_, int id) : authorised(false
CONNECTU(&disconnect_tm, tickEvent, eth, close); CONNECTU(&disconnect_tm, tickEvent, eth, close);
CONNECTU(&streampacker, packetReceiveEvent, this, readed); CONNECTU(&streampacker, packetReceiveEvent, this, readed);
CONNECTU(eth, disconnected, this, disconnected); CONNECTU(eth, disconnected, this, disconnected);
piCoutObj << "client connected" << eth->sendAddress(); piCoutObj << "client connected" << client_id << eth->sendAddress();
} }
@@ -26,6 +26,13 @@ PIString DispatcherClient::address() {
} }
void DispatcherClient::close() { void DispatcherClient::close() {
static_cast<PIThread*>(eth)->stop(false);
eth->close();
}
void DispatcherClient::terminate() {
eth->stop();
eth->close(); eth->close();
} }
@@ -65,10 +72,11 @@ void DispatcherClient::disconnected(bool withError) {
void DispatcherClient::readed(PIByteArray & ba) { void DispatcherClient::readed(PIByteArray & ba) {
// piCout << size;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba); PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
// piCoutObj << "readed" << hdr.first << hdr.second;
if (hdr.first == PICloud::TCP::InvalidType) { if (hdr.first == PICloud::TCP::InvalidType) {
disconnected(true); disconnected(true);
piCoutObj << "invalid message";
return; return;
} }
if (authorised) { if (authorised) {
@@ -80,10 +88,9 @@ void DispatcherClient::readed(PIByteArray & ba) {
disconnected(false); disconnected(false);
return; return;
case PICloud::TCP::Data: case PICloud::TCP::Data:
// piCoutObj << "TCP::Data"; //piCoutObj << "TCP::Data" << tcp.role();
if (tcp.role() == PICloud::TCP::Client) { if (tcp.role() == PICloud::TCP::Client) {
PIByteArray data = tcp.parseData(ba); if (tcp.canParseData(ba)) dataReaded(ba);
if (!data.isEmpty()) dataReaded(data);
else piCoutObj << "invalid data from client"; else piCoutObj << "invalid data from client";
} }
if (tcp.role() == PICloud::TCP::Server) { if (tcp.role() == PICloud::TCP::Server) {
@@ -92,11 +99,15 @@ void DispatcherClient::readed(PIByteArray & ba) {
else piCoutObj << "invalid data from server"; else piCoutObj << "invalid data from server";
} }
return; return;
case PICloud::TCP::Ping:
pingReceived();
return;
default: default:
piCoutObj << "unknown data";
//disconnected(true); //disconnected(true);
return; return;
} }
} } else piCoutObj << "invalid role";
} else { } else {
switch (hdr.first) { switch (hdr.first) {
case PICloud::TCP::Connect: { case PICloud::TCP::Connect: {
@@ -104,7 +115,8 @@ void DispatcherClient::readed(PIByteArray & ba) {
PIByteArray sn = tcp.parseConnect_d(ba); PIByteArray sn = tcp.parseConnect_d(ba);
if (hdr.second == PICloud::TCP::Server) registerServer(sn, this); if (hdr.second == PICloud::TCP::Server) registerServer(sn, this);
if (hdr.second == PICloud::TCP::Client) registerClient(sn, this); if (hdr.second == PICloud::TCP::Client) registerClient(sn, this);
return;} return;
}
case PICloud::TCP::Disconnect: case PICloud::TCP::Disconnect:
disconnected(false); disconnected(false);
return; return;

View File

@@ -13,6 +13,7 @@ public:
~DispatcherClient(); ~DispatcherClient();
void start(); void start();
void close(); void close();
void terminate();
void sendConnected(uint client_id); void sendConnected(uint client_id);
void sendDisconnected(uint client_id); void sendDisconnected(uint client_id);
void sendData(const PIByteArray & data); void sendData(const PIByteArray & data);
@@ -27,6 +28,7 @@ public:
EVENT2(registerClient, const PIByteArray &, sname, DispatcherClient *, client) EVENT2(registerClient, const PIByteArray &, sname, DispatcherClient *, client)
EVENT1(dataReaded, PIByteArray &, ba) EVENT1(dataReaded, PIByteArray &, ba)
EVENT2(dataReadedServer, uint, id, PIByteArray &, ba) EVENT2(dataReadedServer, uint, id, PIByteArray &, ba)
EVENT0(pingReceived)
private: private:
EVENT_HANDLER1(void, readed, PIByteArray &, data); EVENT_HANDLER1(void, readed, PIByteArray &, data);

View File

@@ -7,6 +7,7 @@ DispatcherServer::DispatcherServer(PIEthernet::Address addr) : eth(PIEthernet::T
max_connections = 1000; max_connections = 1000;
eth.setParameter(PIEthernet::ReuseAddress); eth.setParameter(PIEthernet::ReuseAddress);
eth.setReadAddress(addr); eth.setReadAddress(addr);
// eth.setDebug(false);
CONNECTU(&eth, newConnection, this, newConnection); CONNECTU(&eth, newConnection, this, newConnection);
CONNECTU(&timeout_timer, tickEvent, this, cleanClients); CONNECTU(&timeout_timer, tickEvent, this, cleanClients);
} }
@@ -43,22 +44,38 @@ void DispatcherServer::picoutStatus() {
void DispatcherServer::cleanClients() { void DispatcherServer::cleanClients() {
PIVector<DispatcherClient*> rm;
map_mutex.lock(); map_mutex.lock();
for (auto c: rmrf_clients) {
delete c;
}
rmrf_clients.clear();
for (auto c: clients) { for (auto c: clients) {
if (!index_c_servers.contains(c) && !index_c_clients.contains(c)) { if (!index_c_servers.contains(c) && !index_c_clients.contains(c)) {
if (rm_clients.contains(c)) rm << c; if (!rm_clients.contains(c)) rm_clients << c;
else rm_clients << c;
} else rm_clients.removeAll(c); } else rm_clients.removeAll(c);
} }
auto ss = c_servers.values();
for (auto c: ss) {
if (c->lastPing() > 15.0) {
piCout << "remove Server by ping timeout" << c->getConnection()->clientId();
rmrf_clients << const_cast<DispatcherClient *>(c->getConnection());
}
}
for (auto c: rm_clients) { for (auto c: rm_clients) {
if (clients.contains(c)) rm << c; if (clients.contains(c)) {
rmrf_clients << c;
}
}
for (auto c: rmrf_clients) {
clients.removeAll(c);
if(index_c_servers.contains(c)) {
c_servers.remove(c_servers.key(index_c_servers[c]));
index_c_servers.remove(c);
}
index_c_clients.remove(c);
rm_clients.removeAll(c);
} }
map_mutex.unlock(); map_mutex.unlock();
for (auto c: rm) {
c->close();
// c->deleteLater();
}
} }
@@ -83,6 +100,12 @@ void DispatcherServer::updateConnectionsTile(TileList * tl) {
} }
tl->content << TileList::Row(c->address() + " " + role, PIScreenTypes::CellFormat()); tl->content << TileList::Row(c->address() + " " + role, PIScreenTypes::CellFormat());
} }
for (auto c: rm_clients) {
tl->content << TileList::Row("[deleting]" + c->address(), PIScreenTypes::CellFormat());
}
for (auto c: rmrf_clients) {
tl->content << TileList::Row("[NULL]" + c->address(), PIScreenTypes::CellFormat());
}
map_mutex.unlock(); map_mutex.unlock();
} }
@@ -158,37 +181,39 @@ void DispatcherServer::disconnectClient(DispatcherClient *client) {
//piCoutObj << "INVALID client" << client; //piCoutObj << "INVALID client" << client;
return; return;
} }
piCoutObj << "remove client" << client->clientId(); piCoutObj << "remove" << client->clientId();
map_mutex.lock(); map_mutex.lock();
clients.removeOne(client); clients.removeAll(client);
rm_clients.removeAll(client);
CloudServer * cs = index_c_servers.value(client, nullptr); CloudServer * cs = index_c_servers.value(client, nullptr);
if (cs) { if (cs) {
piCoutObj << "remove Server" << client->clientId();
PIVector<DispatcherClient *> cscv = cs->getClients(); PIVector<DispatcherClient *> cscv = cs->getClients();
for(auto csc : cscv) { for(auto csc : cscv) {
clients.removeOne(csc); clients.removeAll(csc);
index_c_clients.removeOne(csc); index_c_clients.remove(csc);
cs->removeClient(csc); cs->removeClient(csc);
csc->close(); csc->close();
csc->deleteLater(); rmrf_clients << csc;
} }
c_servers.remove(cs->serverUUID()); c_servers.remove(cs->serverUUID());
index_c_servers.removeOne(client); index_c_servers.remove(client);
delete cs; delete cs;
} }
CloudServer * cc = index_c_clients.value(client, nullptr); CloudServer * cc = index_c_clients.value(client, nullptr);
if (cc) { if (cc) {
piCoutObj << "remove Client" << client->clientId();
cc->removeClient(client); cc->removeClient(client);
index_c_clients.removeOne(client); index_c_clients.remove(client);
} }
client->close(); client->close();
rmrf_clients << client;
map_mutex.unlock(); map_mutex.unlock();
client->deleteLater();
} }
void DispatcherServer::newConnection(PIEthernet *cl) { void DispatcherServer::newConnection(PIEthernet *cl) {
if (clients.size_s() >= max_connections) { if (clients.size() >= max_connections) {
cl->close();
delete cl; delete cl;
return; return;
} }
@@ -199,6 +224,7 @@ void DispatcherServer::newConnection(PIEthernet *cl) {
CloudServer * cs = c_servers.value(sname, nullptr); CloudServer * cs = c_servers.value(sname, nullptr);
if (cs) { if (cs) {
rm_clients << c; rm_clients << c;
piCoutObj << "dublicate Server ->" << sname.toHex();
} else { } else {
piCoutObj << "add new Server ->" << sname.toHex(); piCoutObj << "add new Server ->" << sname.toHex();
CloudServer * cs = new CloudServer(c, sname); CloudServer * cs = new CloudServer(c, sname);
@@ -213,11 +239,12 @@ void DispatcherServer::newConnection(PIEthernet *cl) {
CloudServer * cs = c_servers.value(sname, nullptr); CloudServer * cs = c_servers.value(sname, nullptr);
if (cs) { if (cs) {
piCoutObj << "add new Client to Server ->" << sname.toHex(); piCoutObj << "add new Client to Server ->" << sname.toHex();
c->authorise(true);
cs->addClient(c); cs->addClient(c);
index_c_clients.insert(c, cs); index_c_clients.insert(c, cs);
c->authorise(true);
} else { } else {
rm_clients << c; rm_clients << c;
piCoutObj << "Client can't connect to Server ->" << sname.toHex();
} }
map_mutex.unlock(); map_mutex.unlock();
}); });

View File

@@ -34,6 +34,7 @@ private:
PIMap<const DispatcherClient *, CloudServer *> index_c_servers; PIMap<const DispatcherClient *, CloudServer *> index_c_servers;
PIMap<const DispatcherClient *, CloudServer *> index_c_clients; PIMap<const DispatcherClient *, CloudServer *> index_c_clients;
PIVector<DispatcherClient*> rm_clients; PIVector<DispatcherClient*> rm_clients;
PIVector<DispatcherClient*> rmrf_clients;
PITimer timeout_timer; PITimer timeout_timer;
PIMutex map_mutex; PIMutex map_mutex;
uint client_gid; uint client_gid;

View File

@@ -193,7 +193,7 @@ void makeEnumInfo(PIFile & f, const PICodeParser::Enum * e) {
} }
void writeClassStreamMembersOut(PIFile & f, const PICodeParser::Entity * e, int & cnt) { void writeClassStreamMembersOut(PIFile & f, const PICodeParser::Entity * e, int & cnt, bool simple) {
PIVector<PICodeParser::Member> ml; PIVector<PICodeParser::Member> ml;
piForeachC (PICodeParser::Member & m, e->members) { piForeachC (PICodeParser::Member & m, e->members) {
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
@@ -208,18 +208,31 @@ void writeClassStreamMembersOut(PIFile & f, const PICodeParser::Entity * e, int
if (m.meta.contains("id")) if (m.meta.contains("id"))
cnt = m.meta.value("id").toInt(); cnt = m.meta.value("id").toInt();
if (m.dims.isEmpty()) { if (m.dims.isEmpty()) {
if (simple) {
f << "\ts << ";
if (parser.isEnum(m.type))
f << "(int)";
f << "v." << m.name << ";\n";
} else {
f << "\tcs << cs.chunk(" << cnt << ", "; f << "\tcs << cs.chunk(" << cnt << ", ";
if (parser.isEnum(m.type)) if (parser.isEnum(m.type))
f << "(int)"; f << "(int)";
f << "v." << m.name << ");\n"; f << "v." << m.name << ");\n";
} else {
PIString ptype = m.type.left(m.type.find('['));
f << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name << "), ";
for (int i = 0; i < m.dims.size_s(); ++i) {
if (i > 0) f << " * ";
f << m.dims[i];
} }
f << "));\n"; } else {
PIString ptype = m.type.left(m.type.find('[')).trim();
PIString size = m.dims[0];
for (int i = 1; i < m.dims.size_s(); ++i) {
size += " * ";
size += m.dims[i];
}
if (simple) {
f << "\tfor (int i = 0; i < " << size << "; ++i)\n";
f << "\t\ts << ((const " << ptype << " *)(v." << m.name << "))[i];\n";
} else {
f << "\tcs << cs.chunk(" << cnt << ", PIVector<" << ptype << " >((const " << ptype << " *)(v." << m.name << "), ";
f << size << "));\n";
}
} }
if (is_union) if (is_union)
break; break;
@@ -227,12 +240,12 @@ void writeClassStreamMembersOut(PIFile & f, const PICodeParser::Entity * e, int
if (is_union) return; if (is_union) return;
piForeachC (PICodeParser::Entity * ce, e->children) { piForeachC (PICodeParser::Entity * ce, e->children) {
if (ce->has_name) continue; if (ce->has_name) continue;
writeClassStreamMembersOut(f, ce, cnt); writeClassStreamMembersOut(f, ce, cnt, simple);
} }
} }
void writeClassStreamMembersIn(PIFile & f, const PICodeParser::Entity * e, int & cnt) { void writeClassStreamMembersIn(PIFile & f, const PICodeParser::Entity * e, int & cnt, bool simple) {
PIVector<PICodeParser::Member> ml; PIVector<PICodeParser::Member> ml;
piForeachC (PICodeParser::Member & m, e->members) { piForeachC (PICodeParser::Member & m, e->members) {
if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue; if (m.is_type_ptr || (m.visibility != PICodeParser::Public)) continue;
@@ -247,31 +260,43 @@ void writeClassStreamMembersIn(PIFile & f, const PICodeParser::Entity * e, int &
if (m.meta.contains("id")) if (m.meta.contains("id"))
cnt = m.meta.value("id").toInt(); cnt = m.meta.value("id").toInt();
if (m.dims.isEmpty()) { if (m.dims.isEmpty()) {
if (simple) {
f << "\ts >> ";
if (parser.isEnum(m.type))
f << "(int&)";
f << "v." << m.name << ";\n";
} else {
f << "\t\tcase " << cnt << ": cs.get("; f << "\t\tcase " << cnt << ": cs.get(";
if (parser.isEnum(m.type)) if (parser.isEnum(m.type))
f << "(int&)"; f << "(int&)";
f << "v." << m.name << "); break;\n"; f << "v." << m.name << "); break;\n";
} else {
PIString ptype = m.type.left(m.type.find('['));
f << "\t\tcase " << cnt << ": {\n\t\t\tPIVector<" << ptype << " > d; cs.get(d);\n";
f << "\t\t\tint cnt = piMini(d.size_s(), ";
for (int i = 0; i < m.dims.size_s(); ++i) {
if (i > 0) f << " * ";
f << m.dims[i];
} }
f << ");\n"; } else {
PIString ptype = m.type.left(m.type.find('[')).trim();
PIString size = m.dims[0];
for (int i = 1; i < m.dims.size_s(); ++i) {
size += " * ";
size += m.dims[i];
}
if (simple) {
f << "\tfor (int i = 0; i < " << size << "; ++i)\n";
f << "\t\ts >> ((" << ptype << " *)(v." << m.name << "))[i];\n";
} else {
f << "\t\tcase " << cnt << ": {\n\t\t\tPIVector<" << ptype << " > d; cs.get(d);\n";
f << "\t\t\tint cnt = piMini(d.size_s(), " << size << ");\n";
f << "\t\t\tfor (int i = 0; i < cnt; ++i)\n"; f << "\t\t\tfor (int i = 0; i < cnt; ++i)\n";
f << "\t\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n"; f << "\t\t\t\t((" << ptype << " *)(v." << m.name << "))[i] = d[i];\n";
f << "\t\t\t}\n"; f << "\t\t\t}\n";
f << "\t\t\tbreak;\n"; f << "\t\t\tbreak;\n";
} }
}
if (is_union) if (is_union)
break; break;
} }
if (is_union) return; if (is_union) return;
piForeachC (PICodeParser::Entity * ce, e->children) { piForeachC (PICodeParser::Entity * ce, e->children) {
if (ce->has_name) continue; if (ce->has_name) continue;
writeClassStreamMembersIn(f, ce, cnt); writeClassStreamMembersIn(f, ce, cnt, simple);
} }
} }
@@ -290,19 +315,26 @@ bool needClassStream(const PICodeParser::Entity * e) {
void makeClassStream(PIFile & f, const PICodeParser::Entity * e) { void makeClassStream(PIFile & f, const PICodeParser::Entity * e) {
if (!needClassStream(e)) return; if (!needClassStream(e)) return;
bool simple = e->meta.contains("simple-stream");
f << "\nPIByteArray & operator <<(PIByteArray & s, const " << e->name << " & v) {\n"; f << "\nPIByteArray & operator <<(PIByteArray & s, const " << e->name << " & v) {\n";
if (!simple)
f << "\tPIChunkStream cs;\n"; f << "\tPIChunkStream cs;\n";
int cnt = 0; int cnt = 0;
writeClassStreamMembersOut(f, e, cnt); writeClassStreamMembersOut(f, e, cnt, simple);
f << "\ts << cs.data();\n\treturn s;\n}\n"; if (!simple)
f << "\ts << cs.data();\n";
f << "\treturn s;\n}\n";
f << "PIByteArray & operator >>(PIByteArray & s, " << e->name << " & v) {\n"; f << "PIByteArray & operator >>(PIByteArray & s, " << e->name << " & v) {\n";
if (!simple) {
f << "\tif (s.size_s() < 4) return s;\n"; f << "\tif (s.size_s() < 4) return s;\n";
f << "\tPIByteArray csba; s >> csba;\n"; f << "\tPIByteArray csba; s >> csba;\n";
f << "\tPIChunkStream cs(csba);\n"; f << "\tPIChunkStream cs(csba);\n";
f << "\twhile (!cs.atEnd()) {\n"; f << "\twhile (!cs.atEnd()) {\n";
f << "\t\tswitch (cs.read()) {\n"; f << "\t\tswitch (cs.read()) {\n";
}
cnt = 0; cnt = 0;
writeClassStreamMembersIn(f, e, cnt); writeClassStreamMembersIn(f, e, cnt, simple);
if (!simple)
f << "\t\t}\n\t}\n"; f << "\t\t}\n\t}\n";
f << "\treturn s;\n}\n"; f << "\treturn s;\n}\n";
} }
@@ -351,17 +383,7 @@ void makeGetterValue(PIFile & f, const PICodeParser::Entity * e) {
void writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool meta, bool enums, bool streams, bool texts, bool getters) { void writeModel(PICodeParser & parser, PICLI & cli, const PIString out, bool meta, bool enums, bool streams, bool texts, bool getters) {
PIVector<const PICodeParser::Entity * > ventities; PIString defname = "CCM_" + PIString::fromNumber(out.hash()) + "_H";
PIString defname = out
.replacedAll('.', '_')
.replaceAll('/', '_')
.replaceAll(':', '_')
.replaceAll('-', '_')
.replaceAll('@', '_')
.replaceAll('\\', '_')
.removeAll(' ')
.toUpperCase()
+ "_H";
PISet<PIString> inc_files; PISet<PIString> inc_files;
piForeachC (PICodeParser::Entity * e, parser.entities) piForeachC (PICodeParser::Entity * e, parser.entities)
if (e->name.find("::") < 0 && !e->name.startsWith("_PI")) if (e->name.find("::") < 0 && !e->name.startsWith("_PI"))

View File

@@ -207,10 +207,19 @@ PIString execute(const PIString & cmd) {
} }
PIStringList filter(const PIString & in, const PIString & f) {
PIStringList ret, lines = in.split("\n");
for (const PIString & l: lines)
if (l.contains(f)) ret << l.trimmed();
return ret;
}
void checkQtLib(PIString lib) { void checkQtLib(PIString lib) {
PIString base = lib.toLowerCase(), pref, suff; PIString base = lib.toLowerCase(), pref, suff;
if (base.startsWith("lib")) {pref += "lib"; base.cutLeft(3);} if (base.startsWith("lib")) {pref += "lib"; base.cutLeft(3);}
if (base.startsWith("qt5")) {pref += "Qt5"; base.cutLeft(3);} if (base.startsWith("qt5")) {pref += "Qt5"; base.cutLeft(3);}
if (base.startsWith("qt6")) {pref += "Qt6"; base.cutLeft(3);}
if (base.startsWith("qt" )) {pref += "Qt" ; base.cutLeft(2);} if (base.startsWith("qt" )) {pref += "Qt" ; base.cutLeft(2);}
if (base.find('.') >= 0) {suff = base.right(base.size_s() - base.find('.')); base = base.left(base.find('.'));} if (base.find('.') >= 0) {suff = base.right(base.size_s() - base.find('.')); base = base.left(base.find('.'));}
for (int i = 0; ; ++i) { for (int i = 0; ; ++i) {
@@ -244,44 +253,34 @@ void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) {
} }
PIStringList lines; PIStringList lines;
if (is_ldd) { if (is_ldd) {
lines = execute(ldd + " " + file).split("\n"); lines = execute(ldd + " \"" + file + "\"").split("\n");
} else { } else {
PIString cmd; PIString cmd;
if (!readelf.isEmpty()) { if (!readelf.isEmpty()) {
cmd = readelf + " -a " + file; lines = filter(execute(readelf + " -a \"" + file + "\""), "Shared library:");
cmd += " | grep \"Shared library:\" | grep -oG \"\\[.*\\]\""; for (PIString & l: lines) {
l.cutRight(1);
l.cutLeft(l.find('[') + 1);
l.trim();//.append('.').prepend('.');
}
} }
if (!objdump.isEmpty()) { if (!objdump.isEmpty()) {
cmd = objdump + " -p " + file; PIString out = execute(objdump + " -p \"" + file + "\"");
cmd += " | grep \"DLL Name:\""; lines = filter(out, "DLL Name:");
lines = execute(cmd).split("\n"); lines << filter(out, "NEEDED");
cmd = objdump + " -p " + file; for (PIString & l: lines) {
cmd += " | grep \"NEEDED\""; if (l.startsWith("DLL")) l.cutLeft(9);
lines << execute(cmd).split("\n"); else l.cutLeft(6);
cmd.clear(); l.trim();//.append('.').prepend('.');
}
if (!otool.isEmpty()) {
cmd = otool + " -L " + file;
cmd += " | grep -o \".*(\"";
}
//piCout << cmd;
if (!cmd.isEmpty())
lines = execute(cmd).split("\n");
if (!objdump.isEmpty()) {
piForeach (PIString & l, lines) {
l.trim();
if (l.startsWith("DLL")) l.cutLeft(9).trim();
else l.cutLeft(6).trim();
l.append('.').prepend('.');
} }
} }
if (!otool.isEmpty()) { if (!otool.isEmpty()) {
lines = filter(execute(otool + " -L \"" + file + "\""), "(");
piForeach (PIString & l, lines) { piForeach (PIString & l, lines) {
l.trim().cutRight(1).trim(); l = l.left(l.find('('));
l.append('.').prepend('.'); l.trim();//.append('.').prepend('.');
} }
} }
//piCout << "readelf:" << vs;
} }
piForeachC (PIString & sl, lines) { piForeachC (PIString & sl, lines) {
PIString l = sl.trimmed(); PIString l = sl.trimmed();
@@ -305,7 +304,7 @@ void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) {
continue; continue;
} }
} else { } else {
l.cutLeft(1).cutRight(1).trim(); //l.cutLeft(1).cutRight(1).trim();
if (l.isEmpty()) continue; if (l.isEmpty()) continue;
if (!otool.isEmpty()) { if (!otool.isEmpty()) {
if (!l.startsWith("/usr/local/")) { if (!l.startsWith("/usr/local/")) {
@@ -379,7 +378,7 @@ void procQt() {
PIString qloc = l.trim(); PIString qloc = l.trim();
piCout << "Qt" << qv << "in" << qloc; piCout << "Qt" << qv << "in" << qloc;
PIString qdir; PIString qdir;
PIStringList suffixes({".", "..", "qt5", "../qt5"}); PIStringList suffixes({".", "..", "qt5", "../qt5", "qt6", "../qt6"});
piForeachC (PIString s, suffixes) { piForeachC (PIString s, suffixes) {
PIString qd = qloc + "/" + s + "/plugins/"; PIString qd = qloc + "/" + s + "/plugins/";
if (piDebug) PICout(AddSpaces) << "Qt plugins root try" << qd << "..."; if (piDebug) PICout(AddSpaces) << "Qt plugins root try" << qd << "...";
@@ -392,17 +391,6 @@ void procQt() {
} }
if (qdir.isEmpty()) if (qdir.isEmpty())
break; break;
/*#ifdef WINDOWS
if (qt_dir.isEmpty())
qdir += "/../plugins/";
else
qdir += "/plugins/";
#else
if (qt_dir.isEmpty())
qdir += "/qt5/plugins/";
else
qdir += "/plugins/";
#endif*/
piForeachC (PIString & plugin, pdirs) { piForeachC (PIString & plugin, pdirs) {
PIStringList filters = qt_filters[plugin]; PIStringList filters = qt_filters[plugin];
piForeachC (PIString & f, filters) { piForeachC (PIString & f, filters) {
@@ -471,9 +459,11 @@ void patchNameTool() {
//PICout(DefaultControls) << "map" << f << "->" << (out_dir + frameworkName(f) + "/" + frameworkInternalPath(f)); //PICout(DefaultControls) << "map" << f << "->" << (out_dir + frameworkName(f) + "/" + frameworkInternalPath(f));
} }
piForeach (PIString local_lib, patch_list) { piForeach (PIString local_lib, patch_list) {
cmd = otool + " -L \"" + local_lib; dlibs = filter(execute(otool + " -L \"" + local_lib + "\""), "(");
cmd += "\" | grep -o \".*(\""; piForeach (PIString & l, dlibs) {
dlibs = execute(cmd).split("\n"); l = l.left(l.find('('));
l.trim();
}
if (!dlibs.isEmpty()) { if (!dlibs.isEmpty()) {
execute("chmod +w \"" + local_lib + "\""); execute("chmod +w \"" + local_lib + "\"");
} }

View File

@@ -28,6 +28,7 @@ int main (int argc, char * argv[]) {
# include "piscreentypes.h" # include "piscreentypes.h"
# include "pisharedmemory.h" # include "pisharedmemory.h"
# include "pifile.h" # include "pifile.h"
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# include "../../libs/console/piterminal.cpp" # include "../../libs/console/piterminal.cpp"