Compare commits
53 Commits
zmq
...
a1c1fd8339
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1c1fd8339 | ||
|
|
01b39dc75f | ||
| 07ec32c969 | |||
| 042366e19e | |||
| 948a90fcd9 | |||
| c404688bbd | |||
| aa76a15f40 | |||
|
|
ca20785b53 | ||
|
|
13d0b2f960 | ||
|
|
46571ac39f | ||
| 36d770ea2e | |||
|
|
bc7d129a9e | ||
| 8accc28804 | |||
|
|
62e130f91b | ||
| a009221092 | |||
| dedc35b466 | |||
| 5e33587703 | |||
| 950f6830da | |||
|
|
19a8ca84e6 | ||
|
|
ece3fb1536 | ||
| 0d119502a8 | |||
| cc5951cfc3 | |||
| 61d42e0ac5 | |||
| 127935086c | |||
| 76ed60edf3 | |||
| 3b0a1c70fe | |||
| 186e07e45d | |||
| 047cff7d6e | |||
| 305275e3ac | |||
| efb0d5f4f9 | |||
| 991a074538 | |||
| f82b6c12ee | |||
| 00edfa4ef0 | |||
| 35a3ce6402 | |||
| be3ce454a0 | |||
| 4c85206cfa | |||
| 5ecdcbe46e | |||
| c937d7251a | |||
| 1cc46468c1 | |||
| 5cc8ef1eb0 | |||
| 99e135caa2 | |||
| 9de7045d63 | |||
| 0e65151e9f | |||
| 3c20728210 | |||
| 4c0530d89a | |||
| f5af8a1da9 | |||
| 44b9c37391 | |||
| 97b0b6fc0c | |||
| 1a2e9afaef | |||
| 39a3a23a24 | |||
| ee131921a0 | |||
| f8818c8537 | |||
| b07242226e |
@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0)
|
||||
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
||||
project(pip)
|
||||
set(pip_MAJOR 2)
|
||||
set(pip_MINOR 28)
|
||||
set(pip_REVISION 1)
|
||||
set(pip_MINOR 32)
|
||||
set(pip_REVISION 0)
|
||||
set(pip_SUFFIX )
|
||||
set(pip_COMPANY SHS)
|
||||
set(pip_DOMAIN org.SHS)
|
||||
@@ -284,7 +284,7 @@ endif()
|
||||
if(APPLE)
|
||||
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
|
||||
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)
|
||||
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
|
||||
#message("${ANDROID_NDK}/sysroot/usr/include")
|
||||
@@ -567,8 +567,8 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
|
||||
list(APPEND DOXY_INPUT "\"${F}\"")
|
||||
endforeach(F)
|
||||
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\"")
|
||||
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${DOXY_INPUT}")
|
||||
string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS};DOXYGEN;PIOBJECT;PIOBJECT_SUBCLASS")
|
||||
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${PIP_INCLUDES}")
|
||||
string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS}")
|
||||
add_documentation(doc doc/Doxyfile.in)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL)
|
||||
endif()
|
||||
|
||||
@@ -2164,7 +2164,7 @@ INCLUDE_FILE_PATTERNS =
|
||||
# recursively expanded use the := operator instead of the = operator.
|
||||
# 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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(ð), tcp(&streampacker) {
|
||||
|
||||
eth.setDebug(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,29 +25,36 @@ PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode)
|
||||
tcp.setRole(PICloud::TCP::Client);
|
||||
setName("cloud_client");
|
||||
is_connected = false;
|
||||
CONNECTL(ð, connected, [this](){tcp.sendStart();});
|
||||
is_deleted = false;
|
||||
// setReopenEnabled(false);
|
||||
CONNECTL(ð, connected, [this](){opened_ = true; tcp.sendStart();});
|
||||
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECTL(ð, disconnected, [this](bool){
|
||||
piCoutObj << "disconnected";
|
||||
if (is_deleted) return;
|
||||
bool need_disconn = is_connected;
|
||||
//piCoutObj << "eth disconnected";
|
||||
static_cast<PIThread*>(ð)->stop();
|
||||
opened_ = false;
|
||||
is_connected = false;
|
||||
cond_connect.notifyOne();
|
||||
cond_buff.notifyOne();
|
||||
piMSleep(100);
|
||||
internalDisconnect();
|
||||
if (need_disconn)
|
||||
disconnected();
|
||||
//piCoutObj << "eth disconnected done";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
PICloudClient::~PICloudClient() {
|
||||
eth.close();
|
||||
if (is_connected) {
|
||||
is_connected = false;
|
||||
disconnected();
|
||||
cond_buff.notifyOne();
|
||||
cond_connect.notifyOne();
|
||||
}
|
||||
//piCoutObj << "~PICloudClient()";
|
||||
PIThread::stop();
|
||||
//eth.close();
|
||||
//if (is_connected) disconnected();
|
||||
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() {
|
||||
// piCout << "PICloudClient open device" << path();
|
||||
//piCoutObj << "open";// << path();
|
||||
bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
|
||||
if (op) {
|
||||
mutex_buff.lock();
|
||||
mutex_connect.lock();
|
||||
eth.startThreadedRead();
|
||||
bool conn_ok = cond_connect.waitFor(mutex_buff, (int)eth.readTimeout(), [this](){return isConnected();});
|
||||
piCoutObj << "conn_ok" << conn_ok;
|
||||
mutex_buff.unlock();
|
||||
//piCoutObj << "connecting...";
|
||||
bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout());
|
||||
//piCoutObj << "conn_ok" << conn_ok << is_connected;
|
||||
mutex_connect.unlock();
|
||||
if (!conn_ok) {
|
||||
mutex_connect.lock();
|
||||
eth.stop();
|
||||
eth.close();
|
||||
piMSleep(100);
|
||||
mutex_connect.unlock();
|
||||
}
|
||||
return isConnected();
|
||||
return is_connected;
|
||||
} else {
|
||||
eth.close();
|
||||
//eth.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PICloudClient::closeDevice() {
|
||||
//PIThread::stop();
|
||||
if (is_connected) {
|
||||
is_connected = false;
|
||||
disconnected();
|
||||
cond_buff.notifyOne();
|
||||
cond_connect.notifyOne();
|
||||
internalDisconnect();
|
||||
}
|
||||
eth.stop();
|
||||
if (eth.isOpened()) eth.close();
|
||||
eth.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PICloudClient::readDevice(void * read_to, int max_size) {
|
||||
// piCoutObj << "readDevice";
|
||||
if (!is_connected) return -1;
|
||||
if (is_deleted) return -1;
|
||||
//piCoutObj << "readDevice";
|
||||
if (!is_connected && eth.isClosed()) openDevice();
|
||||
int sz = -1;
|
||||
mutex_buff.lock();
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();});
|
||||
int sz = piMini(max_size, buff.size());
|
||||
memcpy(read_to, buff.data(), sz);
|
||||
buff.remove(0, sz);
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
|
||||
if (is_connected) {
|
||||
sz = piMini(max_size, buff.size());
|
||||
memcpy(read_to, buff.data(), sz);
|
||||
buff.remove(0, sz);
|
||||
}
|
||||
mutex_buff.unlock();
|
||||
if (!is_connected) opened_ = false;
|
||||
//piCoutObj << "readDevice done" << sz;
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
int PICloudClient::writeDevice(const void * data, int size) {
|
||||
if (is_deleted) return -1;
|
||||
// piCoutObj << "writeDevice";
|
||||
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) {
|
||||
mutex_buff.lock();
|
||||
if (is_deleted) return;
|
||||
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
|
||||
//piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second;
|
||||
if (hdr.second == tcp.role()) {
|
||||
switch (hdr.first) {
|
||||
case PICloud::TCP::Connect:
|
||||
if (tcp.parseConnect(ba) == 1) {
|
||||
mutex_connect.lock();
|
||||
is_connected = true;
|
||||
connected();
|
||||
mutex_connect.unlock();
|
||||
cond_connect.notifyOne();
|
||||
connected();
|
||||
}
|
||||
break;
|
||||
case PICloud::TCP::Disconnect:
|
||||
is_connected = false;
|
||||
eth.stop();
|
||||
static_cast<PIThread*>(ð)->stop();
|
||||
opened_ = false;
|
||||
eth.close();
|
||||
disconnected();
|
||||
break;
|
||||
case PICloud::TCP::Data:
|
||||
if (is_connected) {
|
||||
mutex_buff.lock();
|
||||
buff.append(ba);
|
||||
mutex_buff.unlock();
|
||||
cond_buff.notifyOne();
|
||||
}
|
||||
break;
|
||||
@@ -145,7 +172,7 @@ void PICloudClient::_readed(PIByteArray & ba) {
|
||||
}
|
||||
//piCoutObj << "readed" << ba.toHex();
|
||||
}
|
||||
mutex_buff.unlock();
|
||||
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100);
|
||||
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
|
||||
//piCoutObj << "_readed done";
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,17 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode)
|
||||
tcp.setServerName(server_name);
|
||||
setName("cloud_server__" + server_name);
|
||||
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
|
||||
CONNECTL(ð, connected, [this](){tcp.sendStart();});
|
||||
CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();});
|
||||
CONNECTL(ð, disconnected, [this](bool){
|
||||
piCoutObj << "disconnected";
|
||||
static_cast<PIThread*>(ð)->stop();
|
||||
opened_ = false;
|
||||
ping_timer.stop(false);
|
||||
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() {
|
||||
piCout << "PICloudServer open device" << path();
|
||||
//piCout << "PICloudServer open device" << path();
|
||||
bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
|
||||
if (op) {
|
||||
eth.startThreadedRead();
|
||||
ping_timer.start(5000);
|
||||
return true;
|
||||
}
|
||||
ping_timer.stop(false);
|
||||
eth.close();
|
||||
return false;
|
||||
}
|
||||
@@ -67,6 +74,7 @@ bool PICloudServer::openDevice() {
|
||||
|
||||
bool PICloudServer::closeDevice() {
|
||||
eth.stop();
|
||||
ping_timer.stop(false);
|
||||
clients_mutex.lock();
|
||||
for (auto c : clients_) {
|
||||
c->close();
|
||||
@@ -82,7 +90,8 @@ bool PICloudServer::closeDevice() {
|
||||
|
||||
int PICloudServer::readDevice(void * read_to, int max_size) {
|
||||
//piCoutObj << "readDevice";
|
||||
piMSleep(eth.readTimeout());
|
||||
if (!opened_) openDevice();
|
||||
else piMSleep(eth.readTimeout());
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -126,22 +135,26 @@ bool PICloudServer::Client::openDevice() {
|
||||
|
||||
|
||||
bool PICloudServer::Client::closeDevice() {
|
||||
PIThread::stop(false);
|
||||
if (is_connected) {
|
||||
server->clientDisconnect(client_id);
|
||||
is_connected = false;
|
||||
cond_buff.notifyOne();
|
||||
}
|
||||
cond_buff.notifyOne();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int PICloudServer::Client::readDevice(void * read_to, int max_size) {
|
||||
if (!is_connected) return -1;
|
||||
int sz = -1;
|
||||
mutex_buff.lock();
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();});
|
||||
int sz = piMini(max_size, buff.size());
|
||||
memcpy(read_to, buff.data(), sz);
|
||||
buff.remove(0, sz);
|
||||
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
|
||||
if (is_connected) {
|
||||
sz = piMini(max_size, buff.size());
|
||||
memcpy(read_to, buff.data(), sz);
|
||||
buff.remove(0, sz);
|
||||
}
|
||||
mutex_buff.unlock();
|
||||
return sz;
|
||||
}
|
||||
@@ -158,7 +171,7 @@ void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
|
||||
buff.append(ba);
|
||||
cond_buff.notifyOne();
|
||||
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) {
|
||||
tcp.sendDisconnected(id);
|
||||
} else {
|
||||
piCoutObj << "new Client" << id;
|
||||
//piCoutObj << "new Client" << id;
|
||||
Client * c = new Client(this, id);
|
||||
CONNECTU(c, deleted, this, clientDeleted);
|
||||
clients_mutex.lock();
|
||||
@@ -186,7 +199,7 @@ void PICloudServer::_readed(PIByteArray & ba) {
|
||||
} break;
|
||||
case PICloud::TCP::Disconnect: {
|
||||
uint id = tcp.parseDisconnect(ba);
|
||||
piCoutObj << "remove Client" << id;
|
||||
//piCoutObj << "remove Client" << id;
|
||||
clients_mutex.lock();
|
||||
Client * oc = index_clients.value(id, nullptr);
|
||||
clients_mutex.unlock();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "pistreampacker.h"
|
||||
|
||||
|
||||
const char hash_def_key[] = "_picrypt_";
|
||||
const char hash_cloud_key[] = "_picloud_";
|
||||
|
||||
|
||||
PICloud::TCP::Header::Header() {
|
||||
@@ -33,7 +33,7 @@ PICloud::TCP::Header::Header() {
|
||||
|
||||
|
||||
PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) {
|
||||
|
||||
streampacker->setMaxPacketSize(63*1024);
|
||||
}
|
||||
|
||||
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_) {
|
||||
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;
|
||||
ba << header;
|
||||
ba.append(suuid);
|
||||
//mutex_send.lock();
|
||||
streampacker->send(ba);
|
||||
//mutex_send.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +72,9 @@ void PICloud::TCP::sendConnected(uint client_id) {
|
||||
header.type = PICloud::TCP::Connect;
|
||||
PIByteArray ba;
|
||||
ba << header << client_id;
|
||||
// mutex_send.lock();
|
||||
streampacker->send(ba);
|
||||
// mutex_send.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +82,9 @@ void PICloud::TCP::sendDisconnected(uint client_id) {
|
||||
header.type = PICloud::TCP::Disconnect;
|
||||
PIByteArray ba;
|
||||
ba << header << client_id;
|
||||
// mutex_send.lock();
|
||||
streampacker->send(ba);
|
||||
// mutex_send.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -87,8 +93,10 @@ int PICloud::TCP::sendData(const PIByteArray & data) {
|
||||
PIByteArray ba;
|
||||
ba << header;
|
||||
ba.append(data);
|
||||
// piCout << "sendData" << ba.toHex();
|
||||
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
|
||||
mutex_send.lock();
|
||||
streampacker->send(ba);
|
||||
mutex_send.unlock();
|
||||
return data.size_s();
|
||||
}
|
||||
|
||||
@@ -98,11 +106,24 @@ int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) {
|
||||
PIByteArray ba;
|
||||
ba << header << client_id;
|
||||
ba.append(data);
|
||||
mutex_send.lock();
|
||||
streampacker->send(ba);
|
||||
mutex_send.unlock();
|
||||
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> ret;
|
||||
ret.first = InvalidType;
|
||||
@@ -120,11 +141,8 @@ PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteA
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PICloud::TCP::parseData(PIByteArray & ba) {
|
||||
if (header.role == Client) {
|
||||
return ba;
|
||||
}
|
||||
return PIByteArray();
|
||||
bool PICloud::TCP::canParseData(PIByteArray & ba) {
|
||||
return header.role == Client;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +151,7 @@ PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) {
|
||||
ret.first = 0;
|
||||
if (header.role == Server) {
|
||||
ba >> ret.first;
|
||||
ret.second = ba;
|
||||
ret.second.swap(ba);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
#ifdef PIP_CRYPT
|
||||
return crypto_generichash_BYTES;
|
||||
|
||||
@@ -53,8 +53,6 @@ PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
|
||||
_started = false;
|
||||
_send_only = send_only;
|
||||
_reinit = true;
|
||||
//initMcast(PIEthernet::allAddresses());
|
||||
PIThread::start(3000);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +138,6 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
||||
piForeachC (PIEthernet::Address & a, al) {
|
||||
PIEthernet * ce = 0;
|
||||
//piCout << "mcast try" << a;
|
||||
|
||||
if (_channels[Multicast]) {
|
||||
ce = new PIEthernet();
|
||||
ce->setDebug(false);
|
||||
@@ -184,7 +181,6 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
||||
eth_mcast << ce;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (_channels[Loopback]) {
|
||||
@@ -207,11 +203,14 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
||||
|
||||
|
||||
void PIBroadcast::send(const PIByteArray & data) {
|
||||
if (!isRunning()) {
|
||||
reinit();
|
||||
PIThread::start(3000);
|
||||
}
|
||||
PIByteArray cd = cryptData(data);
|
||||
if (cd.isEmpty()) return;
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
piForeach (PIEthernet * e, eth_mcast)
|
||||
e->send(cd);
|
||||
piForeach (PIEthernet * e, eth_mcast) e->send(cd);
|
||||
if (eth_lo) {
|
||||
for (int i = 0; i < lo_pcnt; ++i) {
|
||||
eth_lo->send("127.0.0.1", lo_port + i, cd);
|
||||
@@ -221,30 +220,31 @@ void PIBroadcast::send(const PIByteArray & data) {
|
||||
|
||||
|
||||
void PIBroadcast::startRead() {
|
||||
if (!isRunning()) {
|
||||
_started = false;
|
||||
reinit();
|
||||
PIThread::start(3000);
|
||||
}
|
||||
if (_send_only) return;
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
piForeach (PIEthernet * e, eth_mcast)
|
||||
e->startThreadedRead();
|
||||
if (eth_lo)
|
||||
eth_lo->startThreadedRead();
|
||||
piForeach (PIEthernet * e, eth_mcast) e->startThreadedRead();
|
||||
if (eth_lo) eth_lo->startThreadedRead();
|
||||
_started = true;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::stopRead() {
|
||||
if (isRunning()) stop();
|
||||
PIMutexLocker ml(mcast_mutex);
|
||||
piForeach (PIEthernet * e, eth_mcast)
|
||||
e->stopThreadedRead();
|
||||
if (eth_lo)
|
||||
eth_lo->stopThreadedRead();
|
||||
piForeach (PIEthernet * e, eth_mcast) e->stopThreadedRead();
|
||||
if (eth_lo) eth_lo->stopThreadedRead();
|
||||
_started = false;
|
||||
}
|
||||
|
||||
|
||||
void PIBroadcast::reinit() {
|
||||
initAll(PIEthernet::allAddresses());
|
||||
if (_started)
|
||||
startRead();
|
||||
if (_started) startRead();
|
||||
}
|
||||
|
||||
|
||||
@@ -261,8 +261,6 @@ void PIBroadcast::run() {
|
||||
mcast_mutex.lock();
|
||||
bool r = _reinit, ac = (al != prev_al);
|
||||
mcast_mutex.unlock();
|
||||
if (ac || r)
|
||||
reinit();
|
||||
if (ac)
|
||||
addressesChanged();
|
||||
if (ac || r) reinit();
|
||||
if (ac) addressesChanged();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
if (data.isEmpty()) return;
|
||||
PIByteArray cd;
|
||||
@@ -94,31 +101,12 @@ void PIStreamPacker::send(const PIByteArray & data) {
|
||||
hdr << int(cd.size_s());
|
||||
cd.insert(0, hdr);
|
||||
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) {
|
||||
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
|
||||
else part = PIByteArray(cd.data(pst), max_packet_size);
|
||||
//piCout << "send" << part.size();
|
||||
sendRequest(part);
|
||||
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;
|
||||
if (packet_size == 0)
|
||||
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;
|
||||
} else {
|
||||
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
|
||||
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);
|
||||
if (packet.size_s() == packet_size) {
|
||||
PIByteArray cd;
|
||||
@@ -211,9 +187,6 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
||||
}
|
||||
packet.clear();
|
||||
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(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.;
|
||||
}
|
||||
|
||||
@@ -52,12 +52,15 @@ protected:
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, _readed, PIByteArray &, data);
|
||||
void internalDisconnect();
|
||||
|
||||
PIByteArray buff;
|
||||
PIMutex mutex_buff;
|
||||
PIMutex mutex_connect;
|
||||
PIConditionVariable cond_buff;
|
||||
PIConditionVariable cond_connect;
|
||||
std::atomic_bool is_connected;
|
||||
std::atomic_bool is_deleted;
|
||||
};
|
||||
|
||||
#endif // PICLOUDCLIENT_H
|
||||
|
||||
@@ -78,6 +78,7 @@ private:
|
||||
|
||||
PIVector<Client *> clients_;
|
||||
PIMap<uint, Client *> index_clients;
|
||||
PITimer ping_timer;
|
||||
mutable PIMutex clients_mutex;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "pip_cloud_export.h"
|
||||
#include "pistring.h"
|
||||
#include "pimutex.h"
|
||||
|
||||
|
||||
class PIEthernet;
|
||||
@@ -52,6 +53,7 @@ public:
|
||||
Connect = 1,
|
||||
Disconnect = 2,
|
||||
Data = 3,
|
||||
Ping = 4,
|
||||
};
|
||||
|
||||
TCP(PIStreamPacker * s);
|
||||
@@ -65,8 +67,9 @@ public:
|
||||
void sendDisconnected(uint client_id);
|
||||
int sendData(const PIByteArray & data);
|
||||
int sendData(const PIByteArray & data, uint client_id);
|
||||
void sendPing();
|
||||
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba);
|
||||
PIByteArray parseData(PIByteArray & ba);
|
||||
bool canParseData(PIByteArray & ba);
|
||||
PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba);
|
||||
PIByteArray parseConnect_d(PIByteArray & ba);
|
||||
uint parseConnect(PIByteArray & ba);
|
||||
@@ -84,6 +87,8 @@ private:
|
||||
PIByteArray suuid;
|
||||
PIString server_name;
|
||||
PIStreamPacker * streampacker;
|
||||
PIMutex mutex_send;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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::EnumInfo * > * PICodeInfo::enumsInfo;
|
||||
PIMap<PIString, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#define PICODEINFO_H
|
||||
|
||||
#include "pistringlist.h"
|
||||
#include "pivarianttypes.h"
|
||||
|
||||
|
||||
class PIVariant;
|
||||
|
||||
@@ -77,6 +79,7 @@ struct PIP_EXPORT ClassInfo {
|
||||
|
||||
struct PIP_EXPORT EnumeratorInfo {
|
||||
EnumeratorInfo(const PIString & n = PIString(), int v = 0) {name = n; value = v;}
|
||||
PIVariantTypes::Enumerator toPIVariantEnumerator() {return PIVariantTypes::Enumerator(value, name);}
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
int value;
|
||||
@@ -85,6 +88,7 @@ struct PIP_EXPORT EnumeratorInfo {
|
||||
struct PIP_EXPORT EnumInfo {
|
||||
PIString memberName(int value) const;
|
||||
int memberValue(const PIString & name) const;
|
||||
PIVariantTypes::Enum toPIVariantEnum();
|
||||
MetaMap meta;
|
||||
PIString name;
|
||||
PIVector<PICodeInfo::EnumeratorInfo> members;
|
||||
|
||||
@@ -190,10 +190,39 @@ void PICodeParser::clear() {
|
||||
piForeachC (PIString & d, defs)
|
||||
defines << Define(d, "");
|
||||
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) {
|
||||
static const PIString s_ns = PIStringAscii("::");
|
||||
static const PIString s_bo = PIStringAscii("{\n");
|
||||
static const PIString s_bc = PIStringAscii("\n}\n");
|
||||
static const PIString s_class = PIStringAscii("class");
|
||||
@@ -280,7 +309,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
|
||||
replaceMeta(pfc);
|
||||
|
||||
//piCout << NewLine << "file" << cur_file << pfc;
|
||||
//piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
|
||||
int pl = -1;
|
||||
while (!pfc.isEmpty()) {
|
||||
pfc.trim();
|
||||
@@ -288,7 +317,12 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
|
||||
if (pl == nl) break;
|
||||
pl = nl;
|
||||
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;
|
||||
}
|
||||
if (pfc.left(8) == s_template) {
|
||||
@@ -417,7 +451,7 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
|
||||
int ps = -1;
|
||||
bool def = false;
|
||||
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 << "\nparse class" << ce->name << "namespace" << cur_namespace;
|
||||
while (!fc.isEmpty()) {
|
||||
@@ -1052,10 +1086,10 @@ PIString PICodeParser::procMacros(PIString fc) {
|
||||
|
||||
|
||||
bool PICodeParser::parseDirective(PIString d) {
|
||||
static const PIString s_include = PIStringAscii("include");
|
||||
static const PIString s_define = PIStringAscii("define");
|
||||
static const PIString s_undef = PIStringAscii("undef");
|
||||
static const PIString s_PIMETA = PIStringAscii("PIMETA");
|
||||
static const PIString s_include = PIStringAscii("include");
|
||||
static const PIString s_define = PIStringAscii("define");
|
||||
static const PIString s_undef = PIStringAscii("undef");
|
||||
static const PIString s_PIMETA = PIStringAscii("PIMETA");
|
||||
if (d.isEmpty()) return true;
|
||||
PIString dname = d.takeCWord();
|
||||
//piCout << "parseDirective" << d;
|
||||
@@ -1074,9 +1108,19 @@ bool PICodeParser::parseDirective(PIString d) {
|
||||
if (mname == s_PIMETA) return true;
|
||||
if (d.left(1) == PIChar('(')) { // macro
|
||||
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);
|
||||
} else { // define
|
||||
d.trim();
|
||||
for (int i = 0; i < defines.size_s(); ++i)
|
||||
if (defines[i].first == mname) {
|
||||
defines.remove(i);
|
||||
break;
|
||||
}
|
||||
defines << Define(mname, d);
|
||||
evaluator.setVariable(mname, complexd_1);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#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
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
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))
|
||||
resize(piv_size, f);
|
||||
}
|
||||
@@ -174,6 +174,20 @@ public:
|
||||
inline size_t capacity() const {return pid_rsize;}
|
||||
inline size_t _start() const {return pid_start;}
|
||||
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 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 T & front() {return pid_data[pid_start];}
|
||||
inline const T & front() const {return pid_data[pid_start];}
|
||||
inline bool operator ==(const PIDeque<T> & t) const {
|
||||
if (pid_size != t.pid_size) return false;
|
||||
for (size_t i = 0; i < pid_size; ++i)
|
||||
if (t[i] != (*this)[i])
|
||||
inline bool operator ==(const PIDeque<T> & v) const {
|
||||
if (pid_size != v.pid_size) return false;
|
||||
for (size_t i = 0; i < pid_size; ++i) {
|
||||
if (v[i] != (*this)[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
inline bool operator !=(const PIDeque<T> & t) const {return !(*this == t);}
|
||||
inline bool operator >(const PIDeque<T> & t) const {
|
||||
if (pid_size != t.pid_size) return pid_size > t.pid_size;
|
||||
for (size_t i = 0; i < pid_size; ++i)
|
||||
if (t[i] != (*this)[i]) return t[i] > (*this)[i];
|
||||
inline bool operator !=(const PIDeque<T> & v) const {return !(*this == v);}
|
||||
inline bool operator <(const PIDeque<T> & v) const {
|
||||
if (pid_size != v.pid_size) return pid_size < v.pid_size;
|
||||
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 & v) const {
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
|
||||
if (v == pid_data[i])
|
||||
inline bool operator >(const PIDeque<T> & v) const {
|
||||
if (pid_size != v.pid_size) return pid_size > v.pid_size;
|
||||
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 false;
|
||||
}
|
||||
inline int etries(const T & v) const {
|
||||
inline int etries(const T & e, size_t start = 0) const {
|
||||
int ec = 0;
|
||||
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
|
||||
if (v == pid_data[i]) ++ec;
|
||||
if (start >= pid_size) return ec;
|
||||
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
|
||||
if (e == pid_data[i]) ++ec;
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
inline ssize_t indexOf(const T & v) const {
|
||||
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i)
|
||||
if (v == pid_data[i])
|
||||
inline int etries(std::function<bool(const T & e)> test, size_t start = 0) const {
|
||||
int ec = 0;
|
||||
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 -1;
|
||||
}
|
||||
inline ssize_t lastIndexOf(const T & v) const {
|
||||
for (ssize_t i = pid_start + (ssize_t)pid_size - 1; i >= pid_start; --i)
|
||||
if (v == pid_data[i])
|
||||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, 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 (test(pid_data[i])) {
|
||||
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;
|
||||
}
|
||||
|
||||
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]);}
|
||||
|
||||
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<
|
||||
!std::is_trivially_copyable<T1>::value
|
||||
, int>::type = 0>
|
||||
@@ -244,15 +312,17 @@ public:
|
||||
inline PIDeque<T> & fill(const T & f = T()) {
|
||||
deleteT(pid_data + pid_start, 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);
|
||||
}
|
||||
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);
|
||||
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));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & assign(const T & f = T()) {return fill(f);}
|
||||
@@ -275,31 +345,35 @@ public:
|
||||
if (new_size < pid_size) {
|
||||
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
|
||||
pid_size = new_size;
|
||||
if (new_size == 0)
|
||||
if (new_size == 0) {
|
||||
pid_start = (pid_rsize - pid_size) / 2;
|
||||
}
|
||||
}
|
||||
if (new_size > pid_size) {
|
||||
size_t os = pid_size;
|
||||
alloc(new_size, true);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
|
||||
pid_size = new_size;
|
||||
if (new_size == 0)
|
||||
if (new_size == 0) {
|
||||
pid_start = (pid_rsize - pid_size) / 2;
|
||||
}
|
||||
}
|
||||
if (new_size > pid_size) {
|
||||
size_t os = pid_size;
|
||||
alloc(new_size, true);
|
||||
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));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -326,8 +400,8 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & insert(size_t index, const T & v = T()) {
|
||||
if (index == pid_size) return push_back(v);
|
||||
inline PIDeque<T> & insert(size_t index, const T & e = T()) {
|
||||
if (index == pid_size) return push_back(e);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||||
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
|
||||
if (dir) {
|
||||
@@ -338,14 +412,15 @@ public:
|
||||
}
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
elementNew(pid_data + pid_start + index, v);
|
||||
elementNew(pid_data + pid_start + index, e);
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & insert(size_t index, T && v) {
|
||||
if (index == pid_size) return push_back(v);
|
||||
inline PIDeque<T> & insert(size_t index, T && e) {
|
||||
if (index == pid_size) return push_back(e);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||||
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
|
||||
if (dir) {
|
||||
@@ -356,10 +431,11 @@ public:
|
||||
}
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
elementNew(pid_data + pid_start + index, std::move(v));
|
||||
elementNew(pid_data + pid_start + index, std::move(e));
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
|
||||
@@ -369,12 +445,14 @@ public:
|
||||
if (dir) {
|
||||
ssize_t os = pid_size - index;
|
||||
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));
|
||||
}
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
}
|
||||
newT(pid_data + pid_start + index, other.pid_data + other.pid_start, other.pid_size);
|
||||
return *this;
|
||||
@@ -389,9 +467,13 @@ public:
|
||||
size_t os = pid_size - index - count;
|
||||
deleteT(&(pid_data[index + pid_start]), count);
|
||||
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 {
|
||||
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_size -= count;
|
||||
@@ -419,88 +501,114 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & removeOne(const T & v) {
|
||||
for (size_t i = 0; i < pid_size; ++i)
|
||||
if (pid_data[i + pid_start] == v) {
|
||||
inline PIDeque<T> & removeOne(const T & e) {
|
||||
for (size_t i = 0; i < pid_size; ++i) {
|
||||
if (pid_data[i + pid_start] == e) {
|
||||
remove(i);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & removeAll(const T & v) {
|
||||
for (ssize_t i = 0; i < ssize_t(pid_size); ++i)
|
||||
if (pid_data[i + pid_start] == v) {
|
||||
inline PIDeque<T> & removeAll(const T & e) {
|
||||
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
|
||||
if (pid_data[i + pid_start] == e) {
|
||||
remove(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;
|
||||
}
|
||||
|
||||
inline PIDeque<T> & push_back(const T & v) {
|
||||
inline PIDeque<T> & push_back(const T & e) {
|
||||
alloc(pid_size + 1, true);
|
||||
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;
|
||||
}
|
||||
inline PIDeque<T> & push_back(T && v) {
|
||||
inline PIDeque<T> & push_back(T && e) {
|
||||
alloc(pid_size + 1, true);
|
||||
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;
|
||||
}
|
||||
inline PIDeque<T> & append(const T & v) {return push_back(v);}
|
||||
inline PIDeque<T> & append(T && v) {return push_back(std::move(v));}
|
||||
inline PIDeque<T> & append(const PIDeque<T> & t) {
|
||||
assert(&t != this);
|
||||
inline PIDeque<T> & append(const T & e) {return push_back(e);}
|
||||
inline PIDeque<T> & append(T && e) {return push_back(std::move(e));}
|
||||
inline PIDeque<T> & append(const PIDeque<T> & v) {
|
||||
assert(&v != this);
|
||||
size_t ps = pid_size;
|
||||
alloc(pid_size + t.pid_size, true);
|
||||
newT(pid_data + ps + pid_start, t.pid_data + t.pid_start, t.pid_size);
|
||||
alloc(pid_size + v.pid_size, true);
|
||||
newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size);
|
||||
return *this;
|
||||
}
|
||||
inline PIDeque<T> & operator <<(const T & v) {return push_back(v);}
|
||||
inline PIDeque<T> & operator <<(T && v) {return push_back(std::move(v));}
|
||||
inline PIDeque<T> & operator <<(const PIDeque<T> & t) {return append(t);}
|
||||
inline PIDeque<T> & operator <<(const T & e) {return push_back(e);}
|
||||
inline PIDeque<T> & operator <<(T && e) {return push_back(std::move(e));}
|
||||
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(T && v) {insert(0, std::move(v)); return *this;}
|
||||
inline PIDeque<T> & prepend(const T & v) {return push_front(v);}
|
||||
inline PIDeque<T> & prepend(T && v) {return push_front(std::move(v));}
|
||||
inline PIDeque<T> & push_front(const T & e) {insert(0, e); return *this;}
|
||||
inline PIDeque<T> & push_front(T && e) {insert(0, std::move(e)); return *this;}
|
||||
inline PIDeque<T> & prepend(const T & e) {return push_front(e);}
|
||||
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_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_front() {T t(front()); pop_front(); return t;}
|
||||
inline T take_back() {T e(back()); pop_back(); return e;}
|
||||
inline T take_front() {T e(front()); pop_front(); return e;}
|
||||
|
||||
template <typename ST>
|
||||
PIDeque<ST> toType() const {
|
||||
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]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const PIDeque<T> & forEach(std::function<void(const T &)> f) const {
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
const PIDeque<T> & forEach(std::function<void(const T & e)> f) const {
|
||||
for (size_t i = 0; i < pid_size; ++i) {
|
||||
f(pid_data[i + pid_start]);
|
||||
}
|
||||
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);
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
for (size_t i = 0; i < pid_size; ++i) {
|
||||
ret << f(pid_data[i + pid_start]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
PIDeque<T> & forEachInplace(std::function<T(const T &)> f) {
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
PIDeque<T> & forEachInplace(std::function<T(const T & e)> f) {
|
||||
for (size_t i = 0; i < pid_size; ++i)
|
||||
pid_data[i + pid_start] = f(pid_data[i + pid_start]);
|
||||
return *this;
|
||||
}
|
||||
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);
|
||||
for (uint i = 0; i < pid_size; ++i)
|
||||
for (size_t i = 0; i < pid_size; ++i) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -510,14 +618,16 @@ public:
|
||||
assert(rows*cols == pid_size);
|
||||
ret.resize(rows);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (order == byColumn) {
|
||||
for (size_t r = 0; r < rows; r++) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -533,13 +643,16 @@ public:
|
||||
size_t cols = at(0).size();
|
||||
ret.reserve(rows * cols);
|
||||
if (order == byRow) {
|
||||
for (size_t r = 0; r < rows; r++)
|
||||
for (size_t r = 0; r < rows; r++) {
|
||||
ret.append(at(r));
|
||||
}
|
||||
}
|
||||
if (order == byColumn) {
|
||||
for (size_t c = 0; c < cols; c++)
|
||||
for (size_t r = 0; r < rows; r++)
|
||||
for (size_t c = 0; c < cols; c++) {
|
||||
for (size_t r = 0; r < rows; r++) {
|
||||
ret << at(r)[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.resize(rows * cols);
|
||||
return ret;
|
||||
@@ -549,11 +662,13 @@ private:
|
||||
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
|
||||
inline size_t asize(ssize_t s) {
|
||||
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;
|
||||
}
|
||||
ssize_t t = 0, s_ = s - 1;
|
||||
while (s_ >> t)
|
||||
while (s_ >> t) {
|
||||
++t;
|
||||
}
|
||||
return (1 << t);
|
||||
}
|
||||
template<typename T1 = T, typename std::enable_if<
|
||||
@@ -577,8 +692,9 @@ private:
|
||||
inline void deleteT(T * d, size_t sz) {
|
||||
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
|
||||
if ((uchar*)d != 0) {
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
elementDelete(d[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
template<typename T1 = T, typename std::enable_if<
|
||||
@@ -652,10 +768,11 @@ private:
|
||||
}
|
||||
} else {
|
||||
size_t as;
|
||||
if (pid_start + start_offset < 0)
|
||||
if (pid_start + start_offset < 0) {
|
||||
as = asize(pid_rsize - start_offset);
|
||||
else as = pid_rsize;
|
||||
|
||||
} else {
|
||||
as = pid_rsize;
|
||||
}
|
||||
if (as > pid_rsize) {
|
||||
T * td = (T*)(malloc(as * sizeof(T)));
|
||||
ssize_t ns = pid_start + as - pid_rsize;
|
||||
@@ -682,7 +799,15 @@ private:
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
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
|
||||
|
||||
template<typename T>
|
||||
@@ -692,8 +817,7 @@ inline PICout operator <<(PICout s, const PIDeque<T> & v) {
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s << v[i];
|
||||
if (i < v.size() - 1)
|
||||
s << ", ";
|
||||
if (i < v.size() - 1) s << ", ";
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
|
||||
@@ -39,10 +39,10 @@ public:
|
||||
alloc(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))
|
||||
alloc(other.piv_size);
|
||||
newT(piv_data, other.piv_data, piv_size);
|
||||
alloc(v.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) {
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
@@ -53,13 +53,13 @@ public:
|
||||
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
|
||||
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))
|
||||
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))
|
||||
other._reset();
|
||||
v._reset();
|
||||
}
|
||||
inline virtual ~PIVector() {
|
||||
PIINTROSPECTION_CONTAINER_DELETE(T)
|
||||
@@ -69,17 +69,17 @@ public:
|
||||
_reset();
|
||||
}
|
||||
|
||||
inline PIVector<T> & operator =(const PIVector<T> & other) {
|
||||
if (this == &other) return *this;
|
||||
inline PIVector<T> & operator =(const PIVector<T> & v) {
|
||||
if (this == &v) return *this;
|
||||
clear();
|
||||
deleteT(piv_data, piv_size);
|
||||
alloc(other.piv_size);
|
||||
newT(piv_data, other.piv_data, piv_size);
|
||||
alloc(v.piv_size);
|
||||
newT(piv_data, v.piv_data, piv_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & operator =(PIVector<T> && other) {
|
||||
swap(other);
|
||||
inline PIVector<T> & operator =(PIVector<T> && v) {
|
||||
swap(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -174,6 +174,19 @@ public:
|
||||
inline size_t length() const {return piv_size;}
|
||||
inline size_t capacity() const {return piv_rsize;}
|
||||
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 const T & operator [](size_t index) const {return piv_data[index];}
|
||||
@@ -183,42 +196,103 @@ public:
|
||||
inline T & front() {return piv_data[0];}
|
||||
inline const T & front() const {return piv_data[0];}
|
||||
inline bool operator ==(const PIVector<T> & t) const {
|
||||
if (piv_size != t.piv_size)
|
||||
if (piv_size != t.piv_size) {
|
||||
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 true;
|
||||
}
|
||||
inline bool operator !=(const PIVector<T> & t) const {return !(*this == t);}
|
||||
inline bool contains(const T & v) const {
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (v == piv_data[i])
|
||||
return true;
|
||||
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 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;
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (v == piv_data[i]) ++ec;
|
||||
if (start >= piv_size) return ec;
|
||||
for (size_t i = start; i < piv_size; ++i) {
|
||||
if (e == piv_data[i]) ++ec;
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
inline ssize_t indexOf(const T & v) const {
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (v == piv_data[i])
|
||||
inline int etries(std::function<bool(const T & e)> test, size_t start = 0) const {
|
||||
int ec = 0;
|
||||
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 -1;
|
||||
}
|
||||
inline ssize_t lastIndexOf(const T & v) const {
|
||||
for (ssize_t i = piv_size - 1; i >= 0; --i)
|
||||
if (v == piv_data[i])
|
||||
inline ssize_t indexWhere(std::function<bool(const T & e)> test, size_t start = 0) const {
|
||||
if (start >= piv_size) return -1;
|
||||
for (size_t i = start; i < piv_size; ++i) {
|
||||
if (test(piv_data[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;
|
||||
}
|
||||
|
||||
inline T * data(size_t index = 0) {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<
|
||||
!std::is_trivially_copyable<T1>::value
|
||||
, int>::type = 0>
|
||||
@@ -238,15 +312,17 @@ public:
|
||||
inline PIVector<T> & fill(const T & f = T()) {
|
||||
deleteT(piv_data, 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);
|
||||
}
|
||||
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);
|
||||
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));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & assign(const T & f = T()) {return fill(f);}
|
||||
@@ -275,12 +351,13 @@ public:
|
||||
size_t os = piv_size;
|
||||
alloc(new_size);
|
||||
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);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
T * de = &(piv_data[new_size]);
|
||||
deleteT(de, piv_size - new_size);
|
||||
@@ -290,8 +367,9 @@ public:
|
||||
size_t os = piv_size;
|
||||
alloc(new_size);
|
||||
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));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -320,34 +398,35 @@ public:
|
||||
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);
|
||||
if (index < piv_size - 1) {
|
||||
size_t os = piv_size - index - 1;
|
||||
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||||
}
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||||
elementNew(piv_data + index, v);
|
||||
elementNew(piv_data + index, e);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & insert(size_t index, T && v) {
|
||||
inline PIVector<T> & insert(size_t index, T && e) {
|
||||
alloc(piv_size + 1);
|
||||
if (index < piv_size - 1) {
|
||||
size_t os = piv_size - index - 1;
|
||||
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||||
}
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1)
|
||||
elementNew(piv_data + index, std::move(v));
|
||||
elementNew(piv_data + index, std::move(e));
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & insert(size_t index, const PIVector<T> & other) {
|
||||
if (other.isEmpty()) return *this;
|
||||
assert(&other != this);
|
||||
inline PIVector<T> & insert(size_t index, const PIVector<T> & v) {
|
||||
if (v.isEmpty()) return *this;
|
||||
assert(&v != this);
|
||||
ssize_t os = piv_size - index;
|
||||
alloc(piv_size + other.piv_size);
|
||||
if (os > 0)
|
||||
memmove((void*)(&(piv_data[index + other.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||||
newT(piv_data + index, other.piv_data, other.piv_size);
|
||||
alloc(piv_size + v.piv_size);
|
||||
if (os > 0) {
|
||||
memmove((void*)(&(piv_data[index + v.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
|
||||
}
|
||||
newT(piv_data + index, v.piv_data, v.piv_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -364,10 +443,10 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void swap(PIVector<T> & other) {
|
||||
piSwap<T*>(piv_data, other.piv_data);
|
||||
piSwap<size_t>(piv_size, other.piv_size);
|
||||
piSwap<size_t>(piv_rsize, other.piv_rsize);
|
||||
inline void swap(PIVector<T> & v) {
|
||||
piSwap<T*>(piv_data, v.piv_data);
|
||||
piSwap<size_t>(piv_size, v.piv_size);
|
||||
piSwap<size_t>(piv_rsize, v.piv_rsize);
|
||||
}
|
||||
|
||||
typedef int (*CompareFunc)(const T * , const T * );
|
||||
@@ -384,98 +463,126 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline PIVector<T> & removeOne(const T & v) {
|
||||
for (size_t i = 0; i < piv_size; ++i)
|
||||
if (piv_data[i] == v) {
|
||||
inline PIVector<T> & removeOne(const T & e) {
|
||||
for (size_t i = 0; i < piv_size; ++i) {
|
||||
if (piv_data[i] == e) {
|
||||
remove(i);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & removeAll(const T & v) {
|
||||
for (ssize_t i = 0; i < ssize_t(piv_size); ++i)
|
||||
if (piv_data[i] == v) {
|
||||
inline PIVector<T> & removeAll(const T & e) {
|
||||
for (ssize_t i = 0; i < ssize_t(piv_size); ++i) {
|
||||
if (piv_data[i] == e) {
|
||||
remove(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;
|
||||
}
|
||||
|
||||
inline PIVector<T> & push_back(const T & v) {
|
||||
inline PIVector<T> & push_back(const T & e) {
|
||||
alloc(piv_size + 1);
|
||||
PIINTROSPECTION_CONTAINER_USED(T, 1);
|
||||
elementNew(piv_data + piv_size - 1, v);
|
||||
elementNew(piv_data + piv_size - 1, e);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & push_back(T && v) {
|
||||
|
||||
inline PIVector<T> & push_back(T && e) {
|
||||
alloc(piv_size + 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;
|
||||
}
|
||||
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 PIVector<T> & other) {
|
||||
assert(&other != this);
|
||||
|
||||
inline PIVector<T> & append(const T & e) {return push_back(e);}
|
||||
inline PIVector<T> & append(T && e) {return push_back(std::move(e));}
|
||||
inline PIVector<T> & append(const PIVector<T> & v) {
|
||||
assert(&v != this);
|
||||
size_t ps = piv_size;
|
||||
alloc(piv_size + other.piv_size);
|
||||
newT(piv_data + ps, other.piv_data, other.piv_size);
|
||||
alloc(piv_size + v.piv_size);
|
||||
newT(piv_data + ps, v.piv_data, v.piv_size);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & operator <<(const T & v) {return push_back(v);}
|
||||
inline PIVector<T> & operator <<(T && v) {return push_back(std::move(v));}
|
||||
inline PIVector<T> & operator <<(const PIVector<T> & other) {return append(other);}
|
||||
inline PIVector<T> & operator <<(const T & e) {return push_back(e);}
|
||||
inline PIVector<T> & operator <<(T && e) {return push_back(std::move(e));}
|
||||
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(T && v) {insert(0, std::move(v)); return *this;}
|
||||
inline PIVector<T> & prepend(const T & v) {return push_front(v);}
|
||||
inline PIVector<T> & prepend(T && v) {return push_front(std::move(v));}
|
||||
inline PIVector<T> & push_front(const T & e) {insert(0, e); return *this;}
|
||||
inline PIVector<T> & push_front(T && e) {insert(0, std::move(e)); return *this;}
|
||||
inline PIVector<T> & prepend(const T & e) {return push_front(e);}
|
||||
inline PIVector<T> & prepend(T && e) {return push_front(std::move(e));}
|
||||
|
||||
inline PIVector<T> & pop_back() {
|
||||
if (piv_size == 0)
|
||||
return *this;
|
||||
if (piv_size == 0) return *this;
|
||||
resize(piv_size - 1);
|
||||
return *this;
|
||||
}
|
||||
inline PIVector<T> & pop_front() {
|
||||
if (piv_size == 0)
|
||||
return *this;
|
||||
if (piv_size == 0) return *this;
|
||||
remove(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline T take_back() {T t(back()); pop_back(); return t;}
|
||||
inline T take_front() {T t(front()); pop_front(); return t;}
|
||||
inline T take_back() {T e(back()); pop_back(); return e;}
|
||||
inline T take_front() {T e(front()); pop_front(); return e;}
|
||||
|
||||
template <typename ST>
|
||||
PIVector<ST> toType() const {
|
||||
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]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const PIVector<T> & forEach(std::function<void(const T &)> f) const {
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
const PIVector<T> & forEach(std::function<void(const T & e)> f) const {
|
||||
for (size_t i = 0; i < piv_size; ++i) {
|
||||
f(piv_data[i]);
|
||||
}
|
||||
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);
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
for (size_t i = 0; i < piv_size; ++i) {
|
||||
ret << f(piv_data[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
PIVector<T> & forEachInplace(std::function<T(const T &)> f) {
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
PIVector<T> & forEachInplace(std::function<T(const T & e)> f) {
|
||||
for (size_t i = 0; i < piv_size; ++i) {
|
||||
piv_data[i] = f(piv_data[i]);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
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);
|
||||
for (uint i = 0; i < piv_size; ++i)
|
||||
for (size_t i = 0; i < piv_size; ++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;
|
||||
}
|
||||
|
||||
@@ -485,14 +592,16 @@ public:
|
||||
assert(rows*cols == piv_size);
|
||||
ret.resize(rows);
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (order == byColumn) {
|
||||
for (size_t r = 0; r < rows; r++) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -508,13 +617,16 @@ public:
|
||||
size_t cols = at(0).size();
|
||||
ret.reserve(rows * cols);
|
||||
if (order == byRow) {
|
||||
for (size_t r = 0; r < rows; r++)
|
||||
for (size_t r = 0; r < rows; r++) {
|
||||
ret.append(at(r));
|
||||
}
|
||||
}
|
||||
if (order == byColumn) {
|
||||
for (size_t c = 0; c < cols; c++)
|
||||
for (size_t r = 0; r < rows; r++)
|
||||
for (size_t c = 0; c < cols; c++) {
|
||||
for (size_t r = 0; r < rows; r++) {
|
||||
ret << at(r)[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
ret.resize(rows * cols);
|
||||
return ret;
|
||||
@@ -524,8 +636,9 @@ private:
|
||||
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
|
||||
inline size_t asize(size_t s) {
|
||||
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;
|
||||
}
|
||||
ssize_t t = 0, s_ = s - 1;
|
||||
while (s_ >> t) ++t;
|
||||
return (1 << t);
|
||||
@@ -551,8 +664,9 @@ private:
|
||||
inline void deleteT(T * d, size_t sz) {
|
||||
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
|
||||
if ((uchar*)d != 0) {
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
elementDelete(d[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
template<typename T1 = T, typename std::enable_if<
|
||||
@@ -612,7 +726,15 @@ private:
|
||||
|
||||
#ifdef PIP_STD_IOSTREAM
|
||||
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
|
||||
|
||||
template<typename T>
|
||||
@@ -622,8 +744,9 @@ inline PICout operator <<(PICout s, const PIVector<T> & v) {
|
||||
s << "{";
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
s << v[i];
|
||||
if (i < v.size() - 1)
|
||||
if (i < v.size() - 1) {
|
||||
s << ", ";
|
||||
}
|
||||
}
|
||||
s << "}";
|
||||
s.restoreControl();
|
||||
|
||||
@@ -221,22 +221,22 @@ PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
|
||||
}
|
||||
|
||||
|
||||
uchar PIByteArray::checksumPlain8() const {
|
||||
uchar PIByteArray::checksumPlain8(bool inverse) const {
|
||||
uchar c = 0;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i)
|
||||
c += at(i);
|
||||
c = ~(c + 1);
|
||||
if (inverse) c = ~(c + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
uint PIByteArray::checksumPlain32() const {
|
||||
uint PIByteArray::checksumPlain32(bool inverse) const {
|
||||
uint c = 0;
|
||||
int sz = size_s();
|
||||
for (int i = 0; i < sz; ++i)
|
||||
c += at(i) * (i + 1);
|
||||
c = ~(c + 1);
|
||||
if (inverse) c = ~(c + 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
@@ -146,18 +146,18 @@ public:
|
||||
PIByteArray & append(uchar t) {push_back(t); return *this;}
|
||||
|
||||
//! Returns 8-bit checksum
|
||||
//! sum all bytes, add 1, inverse
|
||||
//! sum all bytes, if inverse - add 1, inverse
|
||||
//! Pseudocode:
|
||||
//! sum += at(i);
|
||||
//! return ~(sum + 1)
|
||||
uchar checksumPlain8() const;
|
||||
uchar checksumPlain8(bool inverse = true) const;
|
||||
|
||||
//! 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:
|
||||
//! sum += at(i) * (i + 1);
|
||||
//! return ~(sum + 1)
|
||||
uint checksumPlain32() const;
|
||||
uint checksumPlain32(bool inverse = true) const;
|
||||
|
||||
//! Returns hash
|
||||
uint hash() const;
|
||||
@@ -190,34 +190,39 @@ public:
|
||||
//! \relatesalso PIByteArray @brief Byte arrays compare operator
|
||||
inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {
|
||||
if (v0.size() == v1.size()) {
|
||||
for (uint i = 0; i < v0.size(); ++i)
|
||||
if (v0[i] != v1[i])
|
||||
return v0[i] < v1[i];
|
||||
return false;
|
||||
if (v0.isEmpty()) return false;
|
||||
return memcmp(v0.data(), v1.data(), v0.size()) < 0;
|
||||
}
|
||||
return v0.size() < v1.size();
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray @brief Byte arrays compare operator
|
||||
inline bool operator ==(PIByteArray & f, PIByteArray & s) {
|
||||
if (f.size_s() != s.size_s())
|
||||
return false;
|
||||
for (int i = 0; i < f.size_s(); ++i)
|
||||
if (f[i] != s[i])
|
||||
return false;
|
||||
return true;
|
||||
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 v0.size() > v1.size();
|
||||
}
|
||||
|
||||
//! \relatesalso PIByteArray @brief Byte arrays compare operator
|
||||
inline bool operator !=(PIByteArray & f, PIByteArray & s) {
|
||||
if (f.size_s() != s.size_s())
|
||||
return true;
|
||||
for (int i = 0; i < f.size_s(); ++i)
|
||||
if (f[i] != s[i])
|
||||
return true;
|
||||
inline bool operator ==(const PIByteArray & v0, const PIByteArray & v1) {
|
||||
if (v0.size() == v1.size()) {
|
||||
if (v0.isEmpty()) return true;
|
||||
return memcmp(v0.data(), v1.data(), v0.size()) == 0;
|
||||
}
|
||||
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
|
||||
//! \relatesalso PIByteArray @brief Output to std::ostream operator
|
||||
inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);
|
||||
|
||||
@@ -91,9 +91,11 @@ PIObject::~PIObject() {
|
||||
mutexObjects().lock();
|
||||
objects().removeAll(this);
|
||||
mutexObjects().unlock();
|
||||
piDisconnect(this);
|
||||
deleted(this);
|
||||
piDisconnectAll();
|
||||
}
|
||||
|
||||
|
||||
PIMap<PIString, PIVariant> PIObject::properties() const {
|
||||
PIMap<PIString, PIVariant> ret;
|
||||
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 {
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
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" << src << (void*)(dest) << sig;
|
||||
//piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className();
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
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 << "addConnector" << dest_o << src;
|
||||
dest_o->connectors << src;
|
||||
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s();
|
||||
//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) {
|
||||
if (src == 0 || dest_o == 0 || dest == 0) return false;
|
||||
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 Connection();
|
||||
if (!src->isPIObject()) {
|
||||
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")";
|
||||
return false;
|
||||
return Connection();
|
||||
}
|
||||
if (!dest_o->isPIObject()) {
|
||||
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")";
|
||||
return false;
|
||||
return Connection();
|
||||
}
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
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);
|
||||
if (m_src.isEmpty()) {
|
||||
piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
|
||||
return false;
|
||||
return Connection();
|
||||
}
|
||||
if (m_dest.isEmpty()) {
|
||||
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);
|
||||
int args(0);
|
||||
@@ -311,25 +271,26 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_
|
||||
if (addr_src == 0) {
|
||||
piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className()
|
||||
<< "\" 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;
|
||||
dest_o->connectors << src;
|
||||
//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) {
|
||||
delete f;
|
||||
return false;
|
||||
return Connection();
|
||||
}
|
||||
if (!src->isPIObject()) {
|
||||
piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")";
|
||||
delete f;
|
||||
return false;
|
||||
return Connection();
|
||||
}
|
||||
PIMutexLocker ml(__meta_mutex());
|
||||
PIMutexLocker mls(src->mutex_connect);
|
||||
@@ -338,19 +299,19 @@ bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<v
|
||||
if (m_src.isEmpty()) {
|
||||
piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
|
||||
delete f;
|
||||
return false;
|
||||
return Connection();
|
||||
}
|
||||
if (m_src.size() != 1) {
|
||||
piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
|
||||
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";
|
||||
conn.functor = f;
|
||||
src->connections << conn;
|
||||
//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 _mld(dest->mutex_connect, src != dest);
|
||||
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) {
|
||||
src->connections[i].destroy();
|
||||
src->connections.remove(i);
|
||||
@@ -373,7 +334,7 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
PIMutexLocker _mld(dest->mutex_connect, src != dest);
|
||||
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) {
|
||||
src->connections[i].destroy();
|
||||
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) {
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
for (int i = 0; i < src->connections.size_s(); ++i) {
|
||||
__Connection & cc(src->connections[i]);
|
||||
Connection & cc(src->connections[i]);
|
||||
if (cc.event == sig) {
|
||||
PIObject * dest = cc.dest_o;
|
||||
if (!dest) {
|
||||
src->connections[i].destroy();
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
src->connections[i].destroy();
|
||||
src->connections.remove(i);
|
||||
i--;
|
||||
if (dest) {
|
||||
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
|
||||
PIMutexLocker _mld(dest->mutex_connect, src != dest);
|
||||
#endif
|
||||
@@ -404,37 +365,38 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
|
||||
}
|
||||
|
||||
|
||||
void PIObject::piDisconnect(PIObject * src) {
|
||||
src->deleted(src);
|
||||
PIMutexLocker _ml(src->mutex_connect);
|
||||
PIVector<PIObject * > cv = src->connectors.toVector();
|
||||
void PIObject::piDisconnectAll() {
|
||||
PIMutexLocker _ml(mutex_connect);
|
||||
PIVector<PIObject * > cv = connectors.toVector();
|
||||
// piCout << "disconnect connectors =" << connectors.size();
|
||||
piForeach (PIObject * o, cv) {
|
||||
//piCout << "disconnect"<< src->className()<< o->className();
|
||||
if (!o || (o == src)) continue;
|
||||
// piCout << "disconnect"<< src << o;
|
||||
if (!o || (o == this)) continue;
|
||||
if (!o->isPIObject()) continue;
|
||||
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
|
||||
PIMutexLocker _mld(o->mutex_connect, src != o);
|
||||
PIMutexLocker _mld(o->mutex_connect, this != o);
|
||||
#endif
|
||||
PIVector<__Connection> & oc(o->connections);
|
||||
PIVector<Connection> & oc(o->connections);
|
||||
for (int i = 0; i < oc.size_s(); ++i) {
|
||||
if (oc[i].functor) continue;
|
||||
//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.remove(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
piForeachC (PIObject::__Connection & c, src->connections) {
|
||||
// piCout << "disconnect connections =" << connections.size();
|
||||
piForeachC (PIObject::Connection & c, connections) {
|
||||
if (c.functor) continue;
|
||||
if (!c.dest_o) 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)
|
||||
src->connections[i].destroy();
|
||||
src->connections.clear();
|
||||
for (int i = 0; i < connections.size_s(); ++i)
|
||||
connections[i].destroy();
|
||||
connections.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -444,8 +406,8 @@ void PIObject::updateConnectors() {
|
||||
PIMutexLocker _ml(mutexObjects());
|
||||
piForeach (PIObject * o, objects()) {
|
||||
if (o == this) continue;
|
||||
PIVector<__Connection> & oc(o->connections);
|
||||
piForeach (__Connection & c, oc)
|
||||
PIVector<Connection> & oc(o->connections);
|
||||
piForeach (Connection & c, oc)
|
||||
if (c.dest == this)
|
||||
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 << " count: " << connections.size_s();
|
||||
//printf("dump %d connections\n",connections.size());
|
||||
piForeachC (__Connection & c, connections) {
|
||||
piForeachC (Connection & c, connections) {
|
||||
PIObject * dst = c.dest_o;
|
||||
__MetaFunc ef = methodEH(c.signal);
|
||||
PIString src(c.event);
|
||||
@@ -679,12 +641,58 @@ void PIObject::__MetaData::addScope(const PIString & s, uint shash) {
|
||||
}
|
||||
|
||||
|
||||
void PIObject::__Connection::destroy() {
|
||||
|
||||
|
||||
void PIObject::Connection::destroy() {
|
||||
if (functor) delete functor;
|
||||
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)
|
||||
@@ -700,8 +708,7 @@ PIObject::Deleter::Deleter() {
|
||||
stopping = started = posted = false;
|
||||
CONNECTL(&(PRIVATE->thread), started, [this](){proc();});
|
||||
PRIVATE->thread.startOnce();
|
||||
while (!started)
|
||||
piMSleep(1);
|
||||
while (!started) piMSleep(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -710,8 +717,7 @@ PIObject::Deleter::~Deleter() {
|
||||
stopping = true;
|
||||
PRIVATE->cond_var.notifyAll();
|
||||
#ifndef WINDOWS
|
||||
while (PRIVATE->thread.isRunning())
|
||||
piMSleep(1);
|
||||
while (PRIVATE->thread.isRunning()) piMSleep(1);
|
||||
#endif
|
||||
deleteAll();
|
||||
//piCout << "~Deleter ok";
|
||||
@@ -774,12 +780,9 @@ void PIObject::Deleter::deleteObject(PIObject * o) {
|
||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "...";
|
||||
if (o->isPIObject()) {
|
||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ...";
|
||||
while (o->isInEvent()) {
|
||||
piMSleep(1);
|
||||
}
|
||||
while (o->isInEvent()) piMSleep(1);
|
||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done";
|
||||
if (o->isPIObject())
|
||||
delete o;
|
||||
if (o->isPIObject()) delete o;
|
||||
}
|
||||
//piCout << "[Deleter] delete" << (uintptr_t)o << "done";
|
||||
}
|
||||
|
||||
@@ -50,6 +50,54 @@ public:
|
||||
|
||||
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:
|
||||
uint _signature_;
|
||||
|
||||
@@ -141,33 +189,38 @@ public:
|
||||
PIString methodEHFromAddr(const void * addr) const;
|
||||
|
||||
// / 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 bool 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 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 piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0);
|
||||
static PIObject::Connection piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc);
|
||||
template <typename INPUT, typename... TYPES>
|
||||
static std::function<void()> * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT 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);
|
||||
static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * 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" and handler "ev_h"
|
||||
void piDisconnect(const PIString & sig, PIObject * dest, void * ev_h) {piDisconnect(this, sig, dest, 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);
|
||||
|
||||
//! 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);
|
||||
|
||||
//! Disconnect object "src" from all connections with event name "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
|
||||
static void raiseEvent(PIObject * sender, const uint eventID) {
|
||||
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.functor) {
|
||||
(*(i.functor))();
|
||||
@@ -196,7 +249,7 @@ public:
|
||||
template <typename T0>
|
||||
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0()) {
|
||||
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.functor) {
|
||||
(*((std::function<void(T0)>*)i.functor))(v0);
|
||||
@@ -227,7 +280,7 @@ public:
|
||||
template <typename T0, typename 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) {
|
||||
__Connection i(sender->connections[j]);
|
||||
Connection i(sender->connections[j]);
|
||||
if (i.eventID != eventID) continue;
|
||||
if (i.functor) {
|
||||
(*((std::function<void(T0, T1)>*)i.functor))(v0, v1);
|
||||
@@ -262,7 +315,7 @@ public:
|
||||
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()) {
|
||||
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.functor) {
|
||||
(*((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>
|
||||
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) {
|
||||
__Connection i(sender->connections[j]);
|
||||
Connection i(sender->connections[j]);
|
||||
if (i.eventID != eventID) continue;
|
||||
if (i.functor) {
|
||||
(*((std::function<void(T0, T1, T2, T3)>*)i.functor))(v0, v1, v2, v3);
|
||||
@@ -428,30 +481,6 @@ protected:
|
||||
|
||||
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 {
|
||||
__QueuedEvent(void * sl = 0, void * d = 0, PIObject * d_o = 0, PIObject * s = 0, const PIVector<PIVariantSimple> & v = PIVector<PIVariantSimple>()) {
|
||||
slot = sl;
|
||||
@@ -488,6 +517,8 @@ private:
|
||||
PIVector<__MetaFunc> findEH(const PIString & name) const;
|
||||
__MetaFunc methodEH(const void * addr) const;
|
||||
void updateConnectors();
|
||||
void piDisconnectAll();
|
||||
|
||||
void postQueuedEvent(const __QueuedEvent & e);
|
||||
void eventBegin() {in_event_cnt++;}
|
||||
void eventEnd () {in_event_cnt--;}
|
||||
@@ -500,7 +531,7 @@ private:
|
||||
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_;
|
||||
PISet<PIObject * > connectors;
|
||||
PIVector<__QueuedEvent> events_queue;
|
||||
|
||||
@@ -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.
|
||||
/// Returns PIObject::Connection
|
||||
#define CONNECTU(src, event, dest, 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.
|
||||
/// Returns PIObject::Connection
|
||||
#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.
|
||||
/// Returns PIObject::Connection
|
||||
#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
|
||||
/// Returns PIObject::Connection
|
||||
#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
|
||||
/// Returns PIObject::Connection
|
||||
#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
|
||||
/// Returns PIObject::Connection
|
||||
#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
|
||||
/// Returns PIObject::Connection
|
||||
#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)
|
||||
|
||||
/// \relatesalso PIObject @brief CONNECT is synonym of CONNECT0
|
||||
|
||||
@@ -99,9 +99,6 @@ struct PIP_EXPORT Enum {
|
||||
* @brief Make vector of Enum names
|
||||
*/
|
||||
PIStringList names() const;
|
||||
PIString enum_name;
|
||||
PIString selected;
|
||||
PIVector<Enumerator> enum_list;
|
||||
|
||||
/**
|
||||
* @brief Add PIVariantTypes::Enumerator to Enum
|
||||
@@ -119,6 +116,15 @@ struct PIP_EXPORT Enum {
|
||||
* @brief Add PIVariantTypes::Enumerator element for each name in vector
|
||||
*/
|
||||
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 {
|
||||
|
||||
@@ -58,6 +58,9 @@ public:
|
||||
//! Generate hash from bytearray
|
||||
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
|
||||
static size_t sizeHash();
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ bool PIBinaryLog::threadedRead(uchar *readed, int size) {
|
||||
pausemutex.lock();
|
||||
if (is_pause) {
|
||||
pausemutex.unlock();
|
||||
piMSleep(100);
|
||||
piMSleep(100); // TODO: rewrite with condvar
|
||||
return false;
|
||||
} else if (pause_time > PISystemTime()) {
|
||||
startlogtime += pause_time;
|
||||
@@ -204,22 +204,22 @@ bool PIBinaryLog::threadedRead(uchar *readed, int size) {
|
||||
int dtc;
|
||||
if (is_started) {
|
||||
if (is_pause) {
|
||||
piMSleep(100);
|
||||
piMSleep(100); // TODO: rewrite with condvar
|
||||
return false;
|
||||
}
|
||||
if (delay > 0) {
|
||||
cdelay = delay * play_speed;
|
||||
dtc = int(cdelay) /100;
|
||||
cdelay = delay * play_speed;// TODO: rewrite with condvar
|
||||
dtc = int(cdelay) / 100;// TODO: rewrite with condvar
|
||||
if (play_speed <= 0.) dtc = 2;
|
||||
//piCout << play_speed << dtc;
|
||||
for (int j=0; j<dtc; j++) {
|
||||
cdelay = delay * play_speed;
|
||||
dtc = int(cdelay) /100;
|
||||
piMSleep(100);
|
||||
cdelay = delay * play_speed;// TODO: rewrite with condvar
|
||||
dtc = int(cdelay) / 100;// TODO: rewrite with condvar
|
||||
piMSleep(100);// TODO: rewrite with condvar
|
||||
if (play_speed <= 0.) {dtc = 2; j = 0;}
|
||||
//piCout << " " << play_speed << dtc << j;
|
||||
}
|
||||
cdelay = cdelay - dtc*100;
|
||||
cdelay = cdelay - dtc*100;// TODO: rewrite with condvar
|
||||
PISystemTime::fromMilliseconds(cdelay).sleep();
|
||||
}
|
||||
} else is_started = true;
|
||||
@@ -228,7 +228,7 @@ bool PIBinaryLog::threadedRead(uchar *readed, int size) {
|
||||
case PlayStaticDelay:
|
||||
if (is_started) {
|
||||
if (is_pause) {
|
||||
piMSleep(100);
|
||||
piMSleep(100);// TODO: rewrite with condvar
|
||||
return false;
|
||||
}
|
||||
play_delay.sleep();
|
||||
|
||||
@@ -993,6 +993,7 @@ void PIEthernet::configureFromVariantDevice(const PIPropertyStorage & d) {
|
||||
|
||||
|
||||
PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
//piCout << "PIEthernet::interfaces()";
|
||||
PIEthernet::InterfaceList il;
|
||||
Interface ci;
|
||||
ci.index = -1;
|
||||
@@ -1039,8 +1040,16 @@ PIEthernet::InterfaceList PIEthernet::interfaces() {
|
||||
}
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
} else
|
||||
piCout << "[PIEthernet] GetAdaptersInfo failed with error:" << ret;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
if (pAdapterInfo)
|
||||
HeapFree(GetProcessHeap(), 0, (pAdapterInfo));
|
||||
#else
|
||||
|
||||
@@ -85,6 +85,7 @@ public:
|
||||
};
|
||||
|
||||
//! 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);
|
||||
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ void PIIODevice::check_start(void * data, int delim) {
|
||||
//cout << "check " << tread_started_ << endl;
|
||||
if (open()) {
|
||||
thread_started_ = true;
|
||||
timer.stop();
|
||||
timer.stop(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,6 +289,39 @@ bool PISerial::isRNG() const {return isBit(TIOCM_RNG, "RNG");}
|
||||
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) {
|
||||
if (fd < 0) {
|
||||
piCoutObj << "setBit" << bname << " error: \"" << path() << "\" is not opened!";
|
||||
|
||||
@@ -159,6 +159,12 @@ public:
|
||||
bool isRNG() 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();}
|
||||
|
||||
//! Returns device name
|
||||
|
||||
@@ -36,22 +36,6 @@ public:
|
||||
//! Contructs packer and try to assign \"dev\"
|
||||
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
|
||||
void setMaxPacketSize(int max_size) {max_packet_size = max_size;}
|
||||
@@ -83,6 +67,8 @@ public:
|
||||
bool cryptSizeEnabled() const {return crypt_size;}
|
||||
void setCryptSizeEnabled(bool on);
|
||||
|
||||
void clear();
|
||||
|
||||
|
||||
//! Prepare data for send and raise \a sendRequest() events
|
||||
void send(const PIByteArray & data);
|
||||
@@ -97,12 +83,6 @@ public:
|
||||
//! and \a sendRequest() event to \"dev\" \a PIIODevice::write() handler
|
||||
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(sendRequest, PIByteArray, data)
|
||||
|
||||
@@ -139,7 +119,6 @@ private:
|
||||
int packet_size, crypt_frag_size;
|
||||
ushort packet_sign;
|
||||
int max_packet_size, size_crypted_size;
|
||||
Progress prog_s, prog_r;
|
||||
mutable PIMutex prog_s_mutex, prog_r_mutex;
|
||||
|
||||
};
|
||||
|
||||
@@ -259,7 +259,7 @@ uint PISystemInfo::machineID() {
|
||||
if (ret == 0) {
|
||||
CRC_32 crc = standardCRC_32();
|
||||
ret = crc.calculate(machineKey().toByteArray());
|
||||
piCout << "machineID \"" << machineKey() << "\" =" << PICoutManipulators::Hex << ret;
|
||||
//piCout << "machineID \"" << machineKey() << "\" =" << PICoutManipulators::Hex << ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -329,13 +329,13 @@ bool PIThread::_startThread(void * func) {
|
||||
pthread_attr_destroy(&attr);
|
||||
if (ret == 0) {
|
||||
# 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_);
|
||||
# else
|
||||
# ifdef FREERTOS
|
||||
tid_ = PRIVATE->thread;
|
||||
# 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
|
||||
#else
|
||||
@@ -554,7 +554,7 @@ void PIThread::__thread_func_once__() {
|
||||
void PIThread::runOnce(PIObject * object, const char * handler, const PIString & name) {
|
||||
PIThread * t = new PIThread();
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#include "pitimer.h"
|
||||
#include "pipipelinethread.h"
|
||||
#include "pigrabberbase.h"
|
||||
#include "pithreadpoolexecutor.h"
|
||||
#include "piconditionvar.h"
|
||||
#include "pithreadpoolexecutor.h"
|
||||
#include "pithreadpoolloop.h"
|
||||
|
||||
#endif // PITHREADMODULE_H
|
||||
|
||||
130
libs/main/thread/pithreadpoolloop.cpp
Normal file
130
libs/main/thread/pithreadpoolloop.cpp
Normal 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();
|
||||
}
|
||||
69
libs/main/thread/pithreadpoolloop.h
Normal file
69
libs/main/thread/pithreadpoolloop.h
Normal 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
|
||||
69
main.cpp
69
main.cpp
@@ -2,6 +2,58 @@
|
||||
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
|
||||
PIVector<int> data(10, [](int i)->int{return i;});
|
||||
|
||||
piCout << data;
|
||||
|
||||
PIThreadPoolLoop pool;
|
||||
pool.setFunction([&](int i){
|
||||
data[i] = data[i] + 10;
|
||||
});
|
||||
pool.exec(0, data.size());
|
||||
|
||||
piCout << data;
|
||||
|
||||
return 0;
|
||||
|
||||
PIVector<int> x(20, [](int i) {return i;});
|
||||
piCout << x;
|
||||
piCout << x.any([](int v) {return v == 10;});
|
||||
piCout << x.every([](int v) {return v > 0;});
|
||||
piCout << x.etries([](int v) {return v % 5 == 0;});
|
||||
piCout << x.indexWhere([](int v) {return v % 8 == 0;});
|
||||
piCout << x.indexOf(4, -1);
|
||||
piCout << x.lastIndexOf(1, 0);
|
||||
piCout << x.lastIndexWhere([](int v) {return v % 8 == 0;});
|
||||
PIVector<double> x2 = x.map<double>([](int v) {return v / 10.0;});
|
||||
piCout << x2;
|
||||
piCout << x.reduce<PIString>([](int v, PIString s){return s + PIString::fromNumber(v);});
|
||||
piCout << x.removeWhere([](int v){return v % 2 == 0;});
|
||||
piCout << x.getRange(8, 1);
|
||||
piCout << x.getRange(8, 100);
|
||||
|
||||
piCout << "=====================";
|
||||
|
||||
PIDeque<int> y(20, [](int i) {return i;});
|
||||
piCout << y;
|
||||
piCout << y.any([](int v) {return v == 10;});
|
||||
piCout << y.every([](int v) {return v > 0;});
|
||||
piCout << y.etries([](int v) {return v % 5 == 0;});
|
||||
piCout << y.indexWhere([](int v) {return v % 8 == 0;});
|
||||
piCout << y.indexOf(4, -1);
|
||||
piCout << y.lastIndexOf(1, 0);
|
||||
piCout << y.lastIndexWhere([](int v) {return v % 8 == 0;});
|
||||
PIDeque<double> y2 = y.map<double>([](int v) {return v / 10.0;});
|
||||
piCout << y2;
|
||||
piCout << y.reduce<PIString>([](int v, PIString s){return s + PIString::fromNumber(v);});
|
||||
piCout << y.removeWhere([](int v){return v % 2 == 0;});
|
||||
piCout << y.getRange(8, 1);
|
||||
piCout << y.getRange(8, 100);
|
||||
return 0; // TODO:
|
||||
|
||||
PIByteArray rnd;
|
||||
rnd.resize(1024*1024, 'x');
|
||||
PICLI cli(argc, argv);
|
||||
PITimer tm;
|
||||
cli.addArgument("connect", true);
|
||||
@@ -28,18 +80,25 @@ int main(int argc, char * argv[]) {
|
||||
}));
|
||||
CONNECTL(&c, threadedReadEvent, ([&](uchar * readed, int size){
|
||||
PIByteArray ba(readed, size);
|
||||
PIString str = PIString(ba);
|
||||
piCout << "[Client] data:" << str;
|
||||
if (str == "ping_S") c.write(PIString("pong_S").toByteArray());
|
||||
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](uchar * readed, int size){
|
||||
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());
|
||||
if (str == "ping") {
|
||||
cl->write(PIString("pong").toByteArray());
|
||||
cl->write(rnd);
|
||||
}
|
||||
}));
|
||||
CONNECTL(cl, closed, ([&clients, cl](){
|
||||
cl->stop();
|
||||
|
||||
@@ -25,3 +25,4 @@ endmacro()
|
||||
pip_test(concurrent "")
|
||||
pip_test(math "")
|
||||
pip_test(core "")
|
||||
pip_test(piobject "")
|
||||
|
||||
@@ -1,54 +1,73 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "pimathmatrix.h"
|
||||
|
||||
bool cmpSquareMatrixWithValue(PIMathMatrix<double> matrix, double val, int num) {
|
||||
bool b = true;
|
||||
template<typename Type>
|
||||
bool cmpSquareMatrixWithValue(PIMathMatrix<Type> matrix, Type val, int num) {
|
||||
for(int i = 0; i < num; i++) {
|
||||
for(int j = 0; j < num; j++) {
|
||||
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);
|
||||
for(int i = 0; i < 3; i++) {
|
||||
for(int j = 0; j < 3; j++) {
|
||||
if(i != j) {
|
||||
if(matrix[i][j] != 0.0){
|
||||
ASSERT_TRUE(false);
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
else {
|
||||
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) {
|
||||
auto matrix = PIMathMatrix<double>::identity(3, 3);
|
||||
for(int i = 0; i < 3; i++){
|
||||
for(int j = 0; j < 3; j++){
|
||||
if(i != j){
|
||||
if(matrix[i][j] != 0.0){
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(matrix.element(i,i) != 1.0) {
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < 3; i++) {
|
||||
for(int j = 0; j < 3; j++) {
|
||||
if(matrix.element(i,j) != (i == j ? 1. : 0.))
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(PIMathMatrix_Test, matrixRow) {
|
||||
@@ -57,10 +76,10 @@ TEST(PIMathMatrix_Test, matrixRow) {
|
||||
auto matrix = PIMathMatrix<double>::matrixRow(vector);
|
||||
for(uint i = 0; i < vector.size(); i++) {
|
||||
if(matrix[0][i] != 3.0) {
|
||||
ASSERT_TRUE(false);
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(PIMathMatrix_Test, matrixCol) {
|
||||
@@ -69,10 +88,10 @@ TEST(PIMathMatrix_Test, matrixCol) {
|
||||
auto matrix = PIMathMatrix<double>::matrixCol(vector);
|
||||
for(uint i = 0; i < vector.size(); i++) {
|
||||
if(matrix[i][0] != 3.0) {
|
||||
ASSERT_TRUE(false);
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(PIMathMatrix_Test, setCol) {
|
||||
@@ -83,10 +102,10 @@ TEST(PIMathMatrix_Test, setCol) {
|
||||
matrix.setCol(0, vector);
|
||||
for(uint i = 0; i < vector.size(); i++) {
|
||||
if(matrix[i][0] != 10.0) {
|
||||
ASSERT_TRUE(false);
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(PIMathMatrix_Test, setRow) {
|
||||
@@ -97,10 +116,10 @@ TEST(PIMathMatrix_Test, setRow) {
|
||||
matrix.setRow(0, vector);
|
||||
for(uint i = 0; i < vector.size(); i++) {
|
||||
if(matrix[0][i] != 10.0) {
|
||||
ASSERT_TRUE(false);
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(true);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -5,15 +5,14 @@ const uint rows = 3;
|
||||
const uint cols = 3;
|
||||
|
||||
bool cmpSquareMatrixWithValue(PIMathMatrixT<rows, cols, double> matrix, double val, int num) {
|
||||
bool b = true;
|
||||
for(int i = 0; i < num; i++) {
|
||||
for(int j = 0; j < num; j++) {
|
||||
if(matrix.at(i, j) != val) {
|
||||
b = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(PIMathMatrixT_Test, identity) {
|
||||
|
||||
317
tests/piobject/connect.cpp
Normal file
317
tests/piobject/connect.cpp
Normal 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 << "================";
|
||||
}
|
||||
@@ -22,5 +22,6 @@ if (NOT DEFINED ANDROID_PLATFORM)
|
||||
DEPLOY_DIR ${CMAKE_CURRENT_BINARY_DIR}
|
||||
DESTINATION ${ROOT_DIR}/release
|
||||
DEB_ADD_SERVICE
|
||||
ADD_MANIFEST
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -4,9 +4,12 @@ CloudServer::CloudServer(DispatcherClient * c, const PIByteArray & sname) : serv
|
||||
setName(sname.toHex());
|
||||
server_uuid = sname;
|
||||
CONNECTL(c, dataReadedServer, ([this](uint id, PIByteArray & ba){
|
||||
last_ping.reset();
|
||||
DispatcherClient * cl = index_clients.value(id, nullptr);
|
||||
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) {
|
||||
last_ping.reset();
|
||||
clients << c;
|
||||
index_clients.insert(c->clientId(), c);
|
||||
uint cid = c->clientId();
|
||||
index_clients.insert(cid, c);
|
||||
c->sendConnected(1);
|
||||
server->sendConnected(c->clientId());
|
||||
CONNECTL(c, dataReaded, ([this, c](PIByteArray & ba){
|
||||
server->sendConnected(cid);
|
||||
CONNECTL(c, dataReaded, ([this, cid](PIByteArray & ba){
|
||||
// piCoutObj << c->clientId() << "dataReaded";
|
||||
if (clients.contains(c)) {
|
||||
server->sendDataToClient(ba, c->clientId());
|
||||
}
|
||||
server->sendDataToClient(ba, cid);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
void CloudServer::removeClient(DispatcherClient * c) {
|
||||
last_ping.reset();
|
||||
clients.removeOne(c);
|
||||
index_clients.removeOne(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() {
|
||||
piCout << " " << "Clients for" << server->address() << server_uuid.toHex() << ":";
|
||||
for (auto c: clients) {
|
||||
|
||||
@@ -15,12 +15,14 @@ public:
|
||||
PIVector<DispatcherClient*> getClients();
|
||||
EVENT_HANDLER0(void, printStatus);
|
||||
const DispatcherClient * getConnection() const {return server;}
|
||||
double lastPing();
|
||||
|
||||
private:
|
||||
DispatcherClient * server;
|
||||
PIVector<DispatcherClient*> clients;
|
||||
PIMap<uint, DispatcherClient*> index_clients;
|
||||
PIByteArray server_uuid;
|
||||
PITimeMeasurer last_ping;
|
||||
};
|
||||
|
||||
#endif // CLOUDSERVER_H
|
||||
|
||||
@@ -6,7 +6,7 @@ DispatcherClient::DispatcherClient(PIEthernet * eth_, int id) : authorised(false
|
||||
CONNECTU(&disconnect_tm, tickEvent, eth, close);
|
||||
CONNECTU(&streampacker, packetReceiveEvent, this, readed);
|
||||
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() {
|
||||
static_cast<PIThread*>(eth)->stop(false);
|
||||
eth->close();
|
||||
}
|
||||
|
||||
|
||||
void DispatcherClient::terminate() {
|
||||
eth->stop();
|
||||
eth->close();
|
||||
}
|
||||
|
||||
@@ -65,10 +72,11 @@ void DispatcherClient::disconnected(bool withError) {
|
||||
|
||||
|
||||
void DispatcherClient::readed(PIByteArray & ba) {
|
||||
// piCout << size;
|
||||
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
|
||||
// piCoutObj << "readed" << hdr.first << hdr.second;
|
||||
if (hdr.first == PICloud::TCP::InvalidType) {
|
||||
disconnected(true);
|
||||
piCoutObj << "invalid message";
|
||||
return;
|
||||
}
|
||||
if (authorised) {
|
||||
@@ -80,10 +88,9 @@ void DispatcherClient::readed(PIByteArray & ba) {
|
||||
disconnected(false);
|
||||
return;
|
||||
case PICloud::TCP::Data:
|
||||
// piCoutObj << "TCP::Data";
|
||||
//piCoutObj << "TCP::Data" << tcp.role();
|
||||
if (tcp.role() == PICloud::TCP::Client) {
|
||||
PIByteArray data = tcp.parseData(ba);
|
||||
if (!data.isEmpty()) dataReaded(data);
|
||||
if (tcp.canParseData(ba)) dataReaded(ba);
|
||||
else piCoutObj << "invalid data from client";
|
||||
}
|
||||
if (tcp.role() == PICloud::TCP::Server) {
|
||||
@@ -92,11 +99,15 @@ void DispatcherClient::readed(PIByteArray & ba) {
|
||||
else piCoutObj << "invalid data from server";
|
||||
}
|
||||
return;
|
||||
case PICloud::TCP::Ping:
|
||||
pingReceived();
|
||||
return;
|
||||
default:
|
||||
piCoutObj << "unknown data";
|
||||
//disconnected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else piCoutObj << "invalid role";
|
||||
} else {
|
||||
switch (hdr.first) {
|
||||
case PICloud::TCP::Connect: {
|
||||
@@ -104,7 +115,8 @@ void DispatcherClient::readed(PIByteArray & ba) {
|
||||
PIByteArray sn = tcp.parseConnect_d(ba);
|
||||
if (hdr.second == PICloud::TCP::Server) registerServer(sn, this);
|
||||
if (hdr.second == PICloud::TCP::Client) registerClient(sn, this);
|
||||
return;}
|
||||
return;
|
||||
}
|
||||
case PICloud::TCP::Disconnect:
|
||||
disconnected(false);
|
||||
return;
|
||||
|
||||
@@ -13,6 +13,7 @@ public:
|
||||
~DispatcherClient();
|
||||
void start();
|
||||
void close();
|
||||
void terminate();
|
||||
void sendConnected(uint client_id);
|
||||
void sendDisconnected(uint client_id);
|
||||
void sendData(const PIByteArray & data);
|
||||
@@ -27,6 +28,7 @@ public:
|
||||
EVENT2(registerClient, const PIByteArray &, sname, DispatcherClient *, client)
|
||||
EVENT1(dataReaded, PIByteArray &, ba)
|
||||
EVENT2(dataReadedServer, uint, id, PIByteArray &, ba)
|
||||
EVENT0(pingReceived)
|
||||
|
||||
private:
|
||||
EVENT_HANDLER1(void, readed, PIByteArray &, data);
|
||||
|
||||
@@ -7,6 +7,7 @@ DispatcherServer::DispatcherServer(PIEthernet::Address addr) : eth(PIEthernet::T
|
||||
max_connections = 1000;
|
||||
eth.setParameter(PIEthernet::ReuseAddress);
|
||||
eth.setReadAddress(addr);
|
||||
// eth.setDebug(false);
|
||||
CONNECTU(ð, newConnection, this, newConnection);
|
||||
CONNECTU(&timeout_timer, tickEvent, this, cleanClients);
|
||||
}
|
||||
@@ -43,22 +44,38 @@ void DispatcherServer::picoutStatus() {
|
||||
|
||||
|
||||
void DispatcherServer::cleanClients() {
|
||||
PIVector<DispatcherClient*> rm;
|
||||
map_mutex.lock();
|
||||
for (auto c: rmrf_clients) {
|
||||
delete c;
|
||||
}
|
||||
rmrf_clients.clear();
|
||||
for (auto c: clients) {
|
||||
if (!index_c_servers.contains(c) && !index_c_clients.contains(c)) {
|
||||
if (rm_clients.contains(c)) rm << c;
|
||||
else rm_clients << c;
|
||||
if (!rm_clients.contains(c)) rm_clients << 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) {
|
||||
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();
|
||||
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());
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -158,37 +181,39 @@ void DispatcherServer::disconnectClient(DispatcherClient *client) {
|
||||
//piCoutObj << "INVALID client" << client;
|
||||
return;
|
||||
}
|
||||
piCoutObj << "remove client" << client->clientId();
|
||||
piCoutObj << "remove" << client->clientId();
|
||||
map_mutex.lock();
|
||||
clients.removeOne(client);
|
||||
clients.removeAll(client);
|
||||
rm_clients.removeAll(client);
|
||||
CloudServer * cs = index_c_servers.value(client, nullptr);
|
||||
if (cs) {
|
||||
piCoutObj << "remove Server" << client->clientId();
|
||||
PIVector<DispatcherClient *> cscv = cs->getClients();
|
||||
for(auto csc : cscv) {
|
||||
clients.removeOne(csc);
|
||||
index_c_clients.removeOne(csc);
|
||||
clients.removeAll(csc);
|
||||
index_c_clients.remove(csc);
|
||||
cs->removeClient(csc);
|
||||
csc->close();
|
||||
csc->deleteLater();
|
||||
rmrf_clients << csc;
|
||||
}
|
||||
c_servers.remove(cs->serverUUID());
|
||||
index_c_servers.removeOne(client);
|
||||
index_c_servers.remove(client);
|
||||
delete cs;
|
||||
}
|
||||
CloudServer * cc = index_c_clients.value(client, nullptr);
|
||||
if (cc) {
|
||||
piCoutObj << "remove Client" << client->clientId();
|
||||
cc->removeClient(client);
|
||||
index_c_clients.removeOne(client);
|
||||
index_c_clients.remove(client);
|
||||
}
|
||||
client->close();
|
||||
rmrf_clients << client;
|
||||
map_mutex.unlock();
|
||||
client->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void DispatcherServer::newConnection(PIEthernet *cl) {
|
||||
if (clients.size_s() >= max_connections) {
|
||||
cl->close();
|
||||
if (clients.size() >= max_connections) {
|
||||
delete cl;
|
||||
return;
|
||||
}
|
||||
@@ -199,6 +224,7 @@ void DispatcherServer::newConnection(PIEthernet *cl) {
|
||||
CloudServer * cs = c_servers.value(sname, nullptr);
|
||||
if (cs) {
|
||||
rm_clients << c;
|
||||
piCoutObj << "dublicate Server ->" << sname.toHex();
|
||||
} else {
|
||||
piCoutObj << "add new Server ->" << sname.toHex();
|
||||
CloudServer * cs = new CloudServer(c, sname);
|
||||
@@ -213,11 +239,12 @@ void DispatcherServer::newConnection(PIEthernet *cl) {
|
||||
CloudServer * cs = c_servers.value(sname, nullptr);
|
||||
if (cs) {
|
||||
piCoutObj << "add new Client to Server ->" << sname.toHex();
|
||||
c->authorise(true);
|
||||
cs->addClient(c);
|
||||
index_c_clients.insert(c, cs);
|
||||
c->authorise(true);
|
||||
} else {
|
||||
rm_clients << c;
|
||||
piCoutObj << "Client can't connect to Server ->" << sname.toHex();
|
||||
}
|
||||
map_mutex.unlock();
|
||||
});
|
||||
|
||||
@@ -34,6 +34,7 @@ private:
|
||||
PIMap<const DispatcherClient *, CloudServer *> index_c_servers;
|
||||
PIMap<const DispatcherClient *, CloudServer *> index_c_clients;
|
||||
PIVector<DispatcherClient*> rm_clients;
|
||||
PIVector<DispatcherClient*> rmrf_clients;
|
||||
PITimer timeout_timer;
|
||||
PIMutex map_mutex;
|
||||
uint client_gid;
|
||||
|
||||
@@ -351,17 +351,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) {
|
||||
PIVector<const PICodeParser::Entity * > ventities;
|
||||
PIString defname = out
|
||||
.replacedAll('.', '_')
|
||||
.replaceAll('/', '_')
|
||||
.replaceAll(':', '_')
|
||||
.replaceAll('-', '_')
|
||||
.replaceAll('@', '_')
|
||||
.replaceAll('\\', '_')
|
||||
.removeAll(' ')
|
||||
.toUpperCase()
|
||||
+ "_H";
|
||||
PIString defname = "CCM_" + PIString::fromNumber(out.hash()) + "_H";
|
||||
PISet<PIString> inc_files;
|
||||
piForeachC (PICodeParser::Entity * e, parser.entities)
|
||||
if (e->name.find("::") < 0 && !e->name.startsWith("_PI"))
|
||||
|
||||
Reference in New Issue
Block a user