25 Commits

Author SHA1 Message Date
9e5a5970a3 Improved PIBlockingDeque constructors
- resolve creation from constant (see test construct_from_constant_is_max_size_eq_capacity)
- add tests for constructors
2020-08-11 12:30:28 +03:00
46d93c6c9f Improved PIBlockingDeque behaviour and unit tests for put, offer, take methods
- Methods put, offer, take begins working with move and copy semantics
- Mocking queue condition variables with GMock in Unit tests
- Rewrite part of unit tests
2020-08-07 19:12:09 +03:00
662a2fc464 Refactor PIBlockingDequeue 2020-08-07 10:10:05 +03:00
194389ef6d Refactor templates & submit doc 2020-08-06 13:23:49 +03:00
3cfdda7365 PIThreadPoolExecutor & PIBlockingDequeue improvements
- add support move & copy semantic
- introduce submit method for executor with future result
2020-08-05 22:59:33 +03:00
3ec1ecfb5b refactor concurrent module code 2020-08-04 16:39:08 +03:00
be51728570 Merge remote-tracking branch 'origin/master' into concurrent 2020-08-03 17:48:36 +03:00
41e54e5859 Merge pip2 2020-08-03 17:47:19 +03:00
9cd108cf20 tests binary dir fix 2020-08-03 11:10:27 +03:00
22208fbf51 tests binary dir fix 2020-08-03 11:10:05 +03:00
badaa01deb Merge remote-tracking branch 'origin/master' into concurrent
# Conflicts:
#	lib/main/thread/pithreadpoolexecutor.cpp
#	lib/main/thread/pithreadpoolexecutor.h
#	tests/concurrent/ExecutorIntegrationTest.cpp
#	tests/concurrent/ExecutorUnitTest.cpp
#	tests/concurrent/testutil.h
2020-08-03 10:18:52 +03:00
e8a066abcd doc 2020-08-03 09:04:50 +03:00
427e7411c1 move most old PIMap iterators to new
Documentation of PIVector, PIMap and PIMapIterator
2020-08-03 01:43:23 +03:00
df457a1602 rename "iterate" 2020-08-02 19:18:28 +03:00
1dfcaf4952 Merge branch 'master' of https://git.shs.tools/SHS/pip 2020-08-02 15:57:27 +03:00
b468a6d581 PIMapIterator
small PIString optimize
general PIChunkStream pack optimization
2020-08-02 15:57:21 +03:00
b68e8f7a65 Merge picloud branch 2020-08-02 14:00:46 +03:00
1fb5356825 move picompress.h 2020-08-01 23:34:23 +03:00
01f7b15818 remove " " 2020-08-01 23:27:10 +03:00
284971fe8d Merge branch 'master' of https://git.shs.tools/SHS/pip 2020-08-01 23:24:16 +03:00
edacac54f9 PIByteArray rvalue, some fixes 2020-08-01 23:24:08 +03:00
8efd2cf447 Rewrite executor to template & come back executor unit tests 2020-07-17 18:36:28 +03:00
101164902a Merge branch 'master' into picloud 2020-06-28 09:09:59 +03:00
d3ffc19610 Merge commit '02ac4020d3f7a948c87dd0349db093934c0aed3c' into picloud 2020-06-18 19:09:21 +03:00
3f7f67e198 picloud start develop 2020-06-15 11:09:34 +03:00
39 changed files with 1534 additions and 551 deletions

View File

@@ -224,6 +224,7 @@ if (DEFINED LIBPROJECT)
endif()
if (TESTS)
set(PIP_ROOT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}")
add_subdirectory(tests)
endif()
@@ -658,12 +659,14 @@ message(" Modules:")
foreach(_m ${PIP_SRC_MODULES})
message(" ${_m}: ${PIP_MSG_${_m}}")
endforeach()
message("")
if (PIP_TESTS_LIST)
message("")
message(" Tests:")
foreach(_test ${PIP_TESTS_LIST})
message(" * ${_test}")
endforeach()
else()
message(" Tests: skip (tests off)")
endif()
message("")
message(" Utilites:")

View File

@@ -23,3 +23,18 @@
PICloudClient::PICloudClient() {
}
PICloudClient::~PICloudClient() {
}
bool PICloudClient::openDevice() {
}
bool PICloudClient::closeDevice() {
}

View File

@@ -26,14 +26,23 @@
#include "pip_cloud_export.h"
#include "piiodevice.h"
class PIEthernet;
class PIP_CLOUD_EXPORT PICloudClient {
class PIP_CLOUD_EXPORT PICloudClient : public PIIODevice
{
PIIODEVICE(PICloudClient)
public:
//!
explicit PICloudClient();
virtual ~PICloudClient();
protected:
bool openDevice();
bool closeDevice();
private:
PIEthernet * eth;
};
#endif // PICCLOUDCLIENT_H

View File

@@ -108,7 +108,7 @@ void PICodeParser::parseFile(const PIString & file, bool follow_includes) {
piForeachC (Enum & c, enums) {
piCout << PIStringAscii("enum") << c.name << c.meta;
piForeachC (EnumeratorInfo & e, c.members)
piCout << " " << e.name << "=" << e.value << e.meta;
piCout << " " << e.name << '=' << e.value << e.meta;
}
piCout << "\n\nTypedefs:";
piForeachC (Typedef & c, typedefs)
@@ -119,7 +119,7 @@ void PICodeParser::parseFile(const PIString & file, bool follow_includes) {
void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) {
clear();
piForeachC (PIString & f, files)
parseFileInternal(f, follow_includes);
parseFileInternal(f, follow_includes);
/*piCout << "\n\nDefines:";
piForeachC (Define & m, defines)
piCout << PIStringAscii("define") << m.first << m.second;
@@ -277,11 +277,11 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
int nl = pfc.size_s();
if (pl == nl) break;
pl = nl;
if (pfc.left(9) == "namespace") {
if (pfc.left(9) == PIStringAscii("namespace")) {
pfc.cutLeft(pfc.find('{') + 1);
continue;
}
if (pfc.left(8) == "template") {
if (pfc.left(8) == PIStringAscii("template")) {
pfc.cutLeft(8);
pfc.takeRange('<', '>');
bool def = !isDeclaration(pfc, 0, &end);
@@ -290,11 +290,11 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
else pfc.takeSymbol();
continue;
}
if (pfc.left(5) == PIStringAscii("class") || pfc.left(6) == "struct" || pfc.left(5) == "union") {
if (pfc.left(5) == PIStringAscii("class") || pfc.left(6) == PIStringAscii("struct") || pfc.left(5) == PIStringAscii("union")) {
int dind = pfc.find('{', 0), find = pfc.find(';', 0);
if (dind < 0 && find < 0) {pfc.cutLeft(6); continue;}
if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;}
ccmn = pfc.left(dind) + "{\n" + pfc.mid(dind).takeRange('{', '}') + "\n}\n";
ccmn = pfc.left(dind) + PIStringAscii("{\n") + pfc.mid(dind).takeRange('{', '}') + PIStringAscii("\n}\n");
pfc.remove(0, ccmn.size());
parseClass(0, ccmn);
continue;
@@ -363,7 +363,7 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
cur_def_vis = (is_class ? Private : Public);
PIString cn = cd.mid(6).trim();
bool has_name = !cn.isEmpty();
if (cn.isEmpty()) cn = "<unnamed_" + PIString::fromNumber(anon_num++) + '>';
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
//piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return 0;
Entity * e = new Entity();
@@ -393,7 +393,7 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
int ps = -1;
bool def = false;
PIString prev_namespace = cur_namespace, stmp;
cur_namespace = ce->name + "::";
cur_namespace = ce->name + PIStringAscii("::");
//piCout << "parse class" << ce->name << "namespace" << cur_namespace;
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) {
@@ -425,7 +425,7 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
}
if (cw == PIStringAscii("friend")) {fc.cutLeft(fc.find(';') + 1); continue;}
if (cw == PIStringAscii("typedef")) {ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';'))); typedefs << ce->typedefs.back(); typedefs.back().first.insert(0, cur_namespace); if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back(); fc.takeSymbol(); continue;}
if (cw == "template") {
if (cw == PIStringAscii("template")) {
fc.takeRange('<', '>');
def = !isDeclaration(fc, 0, &end);
fc.cutLeft(end);
@@ -453,7 +453,7 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
if (fc.isEmpty()) return ret;
PIStringList ml = fc.split(',');
piForeachC (PIString & m, ml) {
int i = m.find("=");
int i = m.find('=');
if (i < 0) continue;
PIString mv = m.mid(i + 1).trim();
if (mv.startsWith('\"')) mv.cutLeft(1);
@@ -466,6 +466,8 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta) {
static const PIString s_ss = PIStringAscii(" ");
static const PIString s_M = PIStringAscii("$M");
//piCout << PIStringAscii("enum") << name << fc;
Enum e(name);
e.meta = meta;
@@ -474,12 +476,12 @@ bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc
int cv = -1, ind = 0;
piForeach (PIString & v, vl) {
MetaMap meta;
int mi = v.find(PIStringAscii("$M"));
int mi = v.find(s_M);
if (mi >= 0) {
meta = tmp_meta.value(v.takeMid(mi, 5));
v.replaceAll(" ", ' ');
v.replaceAll(s_ss, ' ');
}
vn = v; ind = v.find("=");
vn = v; ind = v.find('=');
if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);}
if (ind < 0) ++cv;
e.members << EnumeratorInfo(vn.trim(), cv, meta);
@@ -512,8 +514,27 @@ PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
static const PIString s_operator = PIStringAscii("operator");
static const PIString s_ss = PIStringAscii(" ");
static const PIString s_cs = PIStringAscii(", ");
static const PIString s_sb = PIStringAscii(" (");
static const PIString s_sM = PIStringAscii(" $M");
static const PIString s_M = PIStringAscii("$M");
static const PIString s_T = PIStringAscii("$T");
static const PIString s_inline_s = PIStringAscii("inline ");
static const PIString s_static_s = PIStringAscii("static ");
static const PIString s_virtual_s = PIStringAscii("virtual ");
static const PIString s_void = PIStringAscii("void");
static const PIString s_using = PIStringAscii("using");
static const PIString s_s5 = PIStringAscii(" ");
static const PIString s_s_const_s = PIStringAscii(" const ");
static const PIString s_s_static_s = PIStringAscii(" static ");
static const PIString s_s_mutable_s = PIStringAscii(" mutable ");
static const PIString s_s_volatile_s = PIStringAscii(" volatile ");
static const PIString s_s_extern_s = PIStringAscii(" extern ");
if (fc.trim().isEmpty()) return true;
if (fc.find("operator") >= 0) return true;
if (fc.find(s_operator) >= 0) return true;
tmp_temp.clear();
//piCout << "parse member" << fc;
int ts = fc.find('<'), te = 0;
@@ -521,22 +542,22 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
while (ts >= 0) {
ctemp = fc.mid(ts).takeRange('<', '>');
if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find('<', te); continue;}
crepl = PIStringAscii("$T") + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0');
crepl = s_T + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0');
fc.replace(ts, ctemp.size_s() + 2, crepl);
tmp_temp[crepl] = '<' + ctemp + '>';
ts = fc.find('<', te);
}
fc.replaceAll('\n', ' ').replaceAll('\t', ' ').replaceAll(" ", ' ').replaceAll(", ", ',').replaceAll(PIStringAscii(" ("), '(').replaceAll(PIStringAscii(" $M"), PIStringAscii("$M"));
fc.replaceAll('\n', ' ').replaceAll('\t', ' ').replaceAll(s_ss, ' ').replaceAll(s_cs, ',').replaceAll(s_sb, '(').replaceAll(s_sM, s_M);
//piCout << "parse member" << fc;
PIStringList tl, al;
Member me;
//piCout << fc;
if (fc.contains('(')) {
MetaMap meta;
int ind = fc.find(PIStringAscii("$M"));
int ind = fc.find(s_M);
if (ind >= 0) {
meta = tmp_meta.value(fc.takeMid(ind, 5));
fc.replaceAll(PIStringAscii(" "), ' ').replaceAll(PIStringAscii(" ("), '(');
fc.replaceAll(s_ss, ' ').replaceAll(s_sb, '(');
}
fc.cutRight(fc.size_s() - fc.findLast(')') - 1);
te = fc.find('(');
@@ -550,26 +571,26 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
me.arguments_full = fc.takeMid(ts + 2).cutRight(1).split(',');
me.type = fc.cutRight(1).trim();
me.visibility = cur_def_vis;
if (me.type.find(PIStringAscii("inline ")) >= 0) {
if (me.type.find(s_inline_s) >= 0) {
me.attributes |= Inline;
me.type.removeAll(PIStringAscii("inline "));
me.type.removeAll(s_inline_s);
}
if (me.type.find(PIStringAscii("static ")) >= 0) {
if (me.type.find(s_static_s) >= 0) {
me.attributes |= Static;
me.type.removeAll(PIStringAscii("static "));
me.type.removeAll(s_static_s);
}
if (me.type.find(PIStringAscii("virtual ")) >= 0) {
if (me.type.find(s_virtual_s) >= 0) {
me.attributes |= Virtual;
me.type.removeAll(PIStringAscii("virtual "));
me.type.removeAll(s_virtual_s);
}
normalizeEntityNamespace(me.type);
int i = 0;
//piCout << me.arguments_full;
piForeach (PIString & a, me.arguments_full)
if ((i = a.find("=")) > 0)
if ((i = a.find('=')) > 0)
a.cutRight(a.size_s() - i).trim();
for (int j = 0; j < me.arguments_full.size_s(); ++j)
if (me.arguments_full[j] == PIStringAscii("void")) {
if (me.arguments_full[j] == s_void) {
me.arguments_full.remove(j);
--j;
}
@@ -590,7 +611,7 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
parent->functions << me;
} else {
if (fc.endsWith(';')) fc.cutRight(1);
if (fc.startsWith(PIStringAscii("using")) || !(fc.contains(' ') || fc.contains('\t') || fc.contains('\n'))) return true;
if (fc.startsWith(s_using) || !(fc.contains(' ') || fc.contains('\t') || fc.contains('\n'))) return true;
int bits = extractMemberBits(fc);
tl = fc.split(',');
//piCout << "member" << fc << tl;
@@ -599,8 +620,8 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
bool vn = true;
ctemp = tl.front().trim();
PIString meta_t;
if (ctemp.contains(PIStringAscii("$M")))
meta_t = ctemp.takeMid(ctemp.find(PIStringAscii("$M")));
if (ctemp.contains(s_M))
meta_t = ctemp.takeMid(ctemp.find(s_M));
for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
@@ -609,26 +630,26 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
me.visibility = cur_def_vis;
ctemp += meta_t;
restoreTmpTemp(&me);
PIString type = PIStringAscii(" ") + me.type;
if (type.find(PIStringAscii(" const ")) >= 0) {
PIString type = s_s5 + me.type;
if (type.find(s_s_const_s) >= 0) {
me.attributes |= Const;
type.replaceAll(PIStringAscii(" const "), ' ');
type.replaceAll(s_s_const_s, ' ');
}
if (type.find(PIStringAscii(" static ")) >= 0) {
if (type.find(s_s_static_s) >= 0) {
me.attributes |= Static;
type.replaceAll(PIStringAscii(" static "), ' ');
type.replaceAll(s_s_static_s, ' ');
}
if (type.find(PIStringAscii(" mutable ")) >= 0) {
if (type.find(s_s_mutable_s) >= 0) {
me.attributes |= Mutable;
type.replaceAll(PIStringAscii(" mutable "), ' ');
type.replaceAll(s_s_mutable_s, ' ');
}
if (type.find(PIStringAscii(" volatile ")) >= 0) {
if (type.find(s_s_volatile_s) >= 0) {
me.attributes |= Volatile;
type.replaceAll(PIStringAscii(" volatile "), ' ');
type.replaceAll(s_s_volatile_s, ' ');
}
if (type.find(PIStringAscii(" extern ")) >= 0) {
if (type.find(s_s_extern_s) >= 0) {
me.attributes |= Extern;
type.replaceAll(PIStringAscii(" extern "), ' ');
type.replaceAll(s_s_extern_s, ' ');
}
type.trim();
normalizeEntityNamespace(type);
@@ -677,6 +698,14 @@ int PICodeParser::extractMemberBits(PIString & fc) {
void PICodeParser::normalizeEntityNamespace(PIString & n) {
static const PIString s_const_s = PIStringAscii("const ");
static const PIString s_static_s = PIStringAscii("static ");
static const PIString s_mutable_s = PIStringAscii("mutable ");
static const PIString s_volatile_s = PIStringAscii("volatile ");
static const PIString s_s_const_s = PIStringAscii(" const ");
static const PIString s_s_static_s = PIStringAscii(" static ");
static const PIString s_s_mutable_s = PIStringAscii(" mutable ");
static const PIString s_s_volatile_s = PIStringAscii(" volatile ");
PIString suff, pref;
for (int i = n.size_s() - 1; i > 0; --i)
if (_isCChar(n[i]) || n[i].isDigit()) {
@@ -685,10 +714,10 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
break;
}
n.push_front(' ');
if (n.find(PIStringAscii(" static ")) >= 0) {n.replaceAll(PIStringAscii(" static "), ""); pref += PIStringAscii("static ");}
if (n.find(PIStringAscii(" const ")) >= 0) {n.replaceAll(PIStringAscii(" const "), ""); pref += PIStringAscii("const ");}
if (n.find(PIStringAscii(" mutable ")) >= 0) {n.replaceAll(PIStringAscii(" mutable "), ""); pref += PIStringAscii("mutable ");}
if (n.find(PIStringAscii(" volatile ")) >= 0) {n.replaceAll(PIStringAscii(" volatile "), ""); pref += PIStringAscii("volatile ");}
if (n.find(s_s_const_s) >= 0) {n.replaceAll(s_s_const_s, ""); pref += s_const_s;}
if (n.find(s_s_static_s) >= 0) {n.replaceAll(s_s_static_s, ""); pref += s_static_s;}
if (n.find(s_s_mutable_s) >= 0) {n.replaceAll(s_s_mutable_s, ""); pref += s_mutable_s;}
if (n.find(s_s_volatile_s) >= 0) {n.replaceAll(s_s_volatile_s, ""); pref += s_volatile_s;}
n.trim();
int f = 0;
piForeachC (Entity * e, entities) {
@@ -697,27 +726,29 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
return;
}
if ((f = e->name.find(n)) >= 0)
if (e->name.mid(f - 1, 1) == PIChar(':'))
if (e->name.at(f - 1) == PIChar(':'))
if (e->name.find(cur_namespace) >= 0) {
n = pref + e->name + suff;
return;
}
}
piForeachC (Enum & e, enums)
if ((f = e.name.find(n)) >= 0)
if (e.name.mid(f - 1, 1) == PIChar(':'))
if (e.name.find(cur_namespace) >= 0) {
//piCout << "change" << n << "to" << e.name + suff;
n = pref + e.name + suff;
return;
piForeachC (Enum & e, enums) {
if ((f = e.name.find(n)) >= 0)
if (e.name.at(f - 1) == PIChar(':'))
if (e.name.find(cur_namespace) >= 0) {
//piCout << "change" << n << "to" << e.name + suff;
n = pref + e.name + suff;
return;
}
}
piForeachC (Typedef & e, typedefs)
if ((f = e.first.find(n)) >= 0)
if (e.first.mid(f - 1, 1) == PIChar(':'))
if (e.first.find(cur_namespace) >= 0) {
//piCout << "change" << n << "to" << e.name + suff;
n = pref + e.first + suff;
return;
piForeachC (Typedef & e, typedefs) {
if ((f = e.first.find(n)) >= 0)
if (e.first.at(f - 1) == PIChar(':'))
if (e.first.find(cur_namespace) >= 0) {
//piCout << "change" << n << "to" << e.name + suff;
n = pref + e.first + suff;
return;
}
}
n = (pref + n + suff).trim();
}
@@ -864,9 +895,9 @@ bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
bool PICodeParser::isMainFile(const PIString & fc) {
int si = 0;
while (si >= 0) {
int csi = fc.find(" main", si);
if (csi < 0) csi = fc.find("\tmain", si);
if (csi < 0) csi = fc.find("\nmain", si);
int csi = fc.find(PIStringAscii(" main"), si);
if (csi < 0) csi = fc.find(PIStringAscii("\tmain"), si);
if (csi < 0) csi = fc.find(PIStringAscii("\nmain"), si);
if (csi < 0) return false;
si = csi;
int fi = fc.find('(', si + 5);
@@ -874,7 +905,7 @@ bool PICodeParser::isMainFile(const PIString & fc) {
if (fi - si < 10) {
PIString ms(fc.mid(si, fi - si + 1));
ms.removeAll(' ').removeAll('\t').removeAll('\n');
if (ms == "main(") return true;
if (ms == PIStringAscii("main(")) return true;
}
si += 5;
}
@@ -925,7 +956,7 @@ PIString PICodeParser::procMacros(PIString fc) {
}
continue;
}
if (mif.left(4) == "else" && ifcnt == 0) {
if (mif.left(4) == PIStringAscii("else") && ifcnt == 0) {
//piCout << "main else" << skip << grab;
if (grab) pfc << procMacros(nfc);
if (skip && !cond_ok) {skip = false; grab = true;}
@@ -959,7 +990,7 @@ bool PICodeParser::parseDirective(PIString d) {
if (d.isEmpty()) return true;
PIString dname = d.takeCWord();
//piCout << "parseDirective" << d;
if (dname == "include") {
if (dname == PIStringAscii("include")) {
d.replaceAll('<', '\"').replaceAll('>', '\"');
PIString cf = cur_file, ifc = d.takeRange('\"', '\"');
if (with_includes) {
@@ -982,7 +1013,7 @@ bool PICodeParser::parseDirective(PIString d) {
}
return true;
}
if (dname == "undef") {
if (dname == PIStringAscii("undef")) {
PIString mname = d.takeCWord();
for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) {defines.remove(i); --i;}

View File

@@ -23,10 +23,11 @@
#ifndef PICOMPRESS_H
#define PICOMPRESS_H
#include "pip_compress_export.h"
#include "pibytearray.h"
PIP_EXPORT PIByteArray piCompress(const PIByteArray & ba, int level = 6);
PIP_COMPRESS_EXPORT PIByteArray piCompress(const PIByteArray & ba, int level = 6);
PIP_EXPORT PIByteArray piDecompress(const PIByteArray & zba);
PIP_COMPRESS_EXPORT PIByteArray piDecompress(const PIByteArray & zba);
#endif // PICOMPRESS_H

View File

@@ -28,147 +28,347 @@
* \fn PIVector::PIVector();
* Contructs an empty vector
* \fn PIVector::PIVector(ullong size, const Type & value = Type());
* \fn PIVector::PIVector(size_t size, const T & value = T());
* \brief Contructs vector with size "size" filled elements "value"
* \details Example: \snippet picontainers.cpp PIVector::PIVector
* \fn const Type & PIVector::at(ullong index) const;
* \fn const T & PIVector::at(size_t index) const;
* \brief Read-only access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::at_c
* \sa \a operator[]
* \fn Type & PIVector::at(ullong index);
* \fn T & PIVector::at(size_t index);
* \brief Full access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::at
* \sa \a operator[]
* \fn const Type * PIVector::data(ullong index = 0) const;
* \fn const T * PIVector::data(size_t index = 0) const;
* \brief Read-only pointer to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::data_c
* \fn Type * PIVector::data(ullong index = 0);
* \fn T * PIVector::data(size_t index = 0);
* \brief Pointer to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::data
* \fn ullong PIVector::size() const;
* \fn size_t PIVector::size() const;
* \brief Elements count
* \fn int PIVector::size_s() const;
* \fn ssize_t PIVector::size_s() const;
* \brief Elements count
* \fn bool PIVector::isEmpty() const;
* \brief Return \c "true" if vector is empty, i.e. size = 0
* \fn bool PIVector::has(const Type & t) const;
* \fn bool PIVector::has(const T & t) const;
* \fn bool PIVector::contains(const Type & v) const;
* \fn bool PIVector::contains(const T & v) const;
* \brief Return \c "true" if vector has at least one element equal "t"
* \fn int PIVector::etries(const Type & t) const;
* \fn int PIVector::etries(const T & t) const;
* \brief Return how many times element "t" appears in vector
* \fn static int PIVector::compare_func(const Type * t0, const Type * t1);
* \brief Standard compare function for type "Type". Return 0 if t0 = t1, -1 if t0 < t1 and 1 if t0 > t1.
* \fn ssize_t PIVector::indexOf(const T & t) const;
* \brief Return index of first element equal "t" or -1 if there is no such element
* \fn void PIVector::resize(ullong size, const Type & new_type = Type());
* \fn ssize_t PIVector::lastIndexOf(const T & t) const;
* \brief Return index of last element equal "t" or -1 if there is no such element
* \fn static int PIVector::compare_func(const T * t0, const T * t1);
* \brief Standard compare function for type "T". Return 0 if t0 = t1, -1 if t0 < t1 and 1 if t0 > t1.
* \fn void PIVector::resize(size_t size, const T & new_type = T());
* \brief Resize vector to size "size"
* \details Elements removed from end of vector if new size < old size, or added new elements = "new_type" if new size > old size.\n
* Example: \snippet picontainers.cpp PIVector::resize
* \sa \a size(), \a clear()
* \fn PIVector<T> & PIVector::enlarge(ullong size);
* \fn PIVector & PIVector::enlarge(size_t size);
* \brief Increase vector size with "size" elements
* \fn void PIVector::clear();
* \brief Clear vector. Equivalent to call <tt>"resize(0)"</tt>
* \fn PIVector<T> & PIVector::sort(CompareFunc compare = compare_func);
* \fn PIVector & PIVector::sort(CompareFunc compare = compare_func);
* \brief Sort vector using quick sort algorithm and standard compare function
* \details Example: \snippet picontainers.cpp PIVector::sort_0
* With custom compare function: \snippet picontainers.cpp PIVector::sort_1
* \fn PIVector<T> & PIVector::fill(const Type & t);
* \fn PIVector & PIVector::fill(const T & t);
* \brief Fill vector with elements "t" leave size is unchanged and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::fill
* \fn Type & PIVector::back();
* \fn PIVector & PIVector::assign(const T & t = T());
* \brief Synonym of \a fill(t)
* \fn PIVector & PIVector::assign(size_t new_size, const T & t);
* \brief Resize to "new_size", then fill with "t"
* \fn T & PIVector::back();
* \brief Last element of the vector
* \fn const Type & PIVector::back() const;
* \fn const T & PIVector::back() const;
* \brief Last element of the vector
* \fn Type & PIVector::front();
* \fn T & PIVector::front();
* \brief First element of the vector
* \fn const Type & PIVector::front() const;
* \fn const T & PIVector::front() const;
* \brief First element of the vector
* \fn PIVector<T> & PIVector::push_back(const Type & t);
* \fn PIVector & PIVector::push_back(const T & t);
* \brief Add new element "t" at the end of vector and return reference to vector
* \fn PIVector<T> & PIVector::push_front(const Type & t);
* \fn PIVector & PIVector::push_front(const T & t);
* \brief Add new element "t" at the beginning of vector and return reference to vector
* \fn PIVector<T> & PIVector::pop_back();
* \fn PIVector & PIVector::pop_back();
* \brief Remove one element from the end of vector and return reference to vector
* \fn PIVector<T> & PIVector::pop_front();
* \fn PIVector & PIVector::pop_front();
* \brief Remove one element from the beginning of vector and return reference to vector
* \fn Type PIVector::take_back();
* \fn T PIVector::take_back();
* \brief Remove one element from the end of vector and return it
* \fn Type PIVector::take_front();
* \fn T PIVector::take_front();
* \brief Remove one element from the beginning of vector and return it
* \fn PIVector<T> & PIVector::remove(uint index);
* \fn PIVector & PIVector::remove(size_t index);
* \brief Remove one element by index "index" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::remove_0
* \sa \a removeOne(), \a removeAll()
* \fn PIVector<T> & PIVector::remove(uint index, uint count);
* \fn PIVector & PIVector::remove(size_t index, size_t count);
* \brief Remove "count" elements by first index "index" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::remove_1
* \sa \a removeOne(), \a removeAll()
* \fn PIVector<T> & PIVector::removeOne(const Type & v);
* \fn PIVector & PIVector::removeOne(const T & v);
* \brief Remove no more than one element equal "v" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::removeOne
* \sa \a remove(), \a removeAll()
* \fn PIVector<T> & PIVector::removeAll(const Type & v);
* \fn PIVector & PIVector::removeAll(const T & v);
* \brief Remove all elements equal "v" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::removeAll
* \sa \a remove(), \a removeOne()
* \fn PIVector<T> & PIVector::insert(uint pos, const Type & t);
* \fn PIVector & PIVector::insert(size_t pos, const T & t);
* \brief Insert element "t" after index "pos" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::insert_0
* \fn PIVector<T> & PIVector::insert(uint pos, const PIVector<T> & t);
* \fn PIVector & PIVector::insert(size_t pos, const PIVector & t);
* \brief Insert other vector "t" after index "pos" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::insert_1
* \fn Type & PIVector::operator [](uint index);
* \fn T & PIVector::operator [](size_t index);
* \brief Full access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::()
* \sa \a at()
* \fn const Type & PIVector::operator [](uint index) const;
* \fn const T & PIVector::operator [](size_t index) const;
* \brief Read-only access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::()_c
* \sa \a at()
* \fn PIVector<T> & PIVector::operator <<(const Type & t);
* \fn PIVector & PIVector::operator <<(const T & t);
* \brief Add new element "t" at the end of vector and return reference to vector
* \fn PIVector<T> & PIVector::operator <<(const PIVector<T> & t);
* \fn PIVector & PIVector::operator <<(const PIVector & t);
* \brief Add vector "t" at the end of vector and return reference to vector
* \fn bool PIVector::operator ==(const PIVector<T> & t);
* \fn bool PIVector::operator ==(const PIVector & t);
* \brief Compare with vector "t"
* \fn bool PIVector::operator !=(const PIVector<T> & t);
* \fn bool PIVector::operator !=(const PIVector & t);
* \brief Compare with vector "t"
* */
/** \class PIMap
* \brief Associative array
* \details This class used to store Key = Value array of any
* type of data. \a value() returns value for key and leave map
* unchaged in any case. \a operator [] create entry in map if
* there is no entry for given key. You can retrieve all
* keys by method \a keys() and all values by methos \a values().
* To iterate all entries use class PIMapIterator, or methods
* \a makeIterator() and \a makeReverseIterator().
* \fn PIMap::PIMap();
* \brief Contructs an empty map
* \fn PIMap::PIMap(const PIMap & other);
* \brief Contructs a copy of "other"
* \fn PIMap & PIMap::operator =(const PIMap & other);
* \brief Copy operator
* \fn PIMap::PIMap(const PIMap & other);
* \brief Contructs a copy of "other"
* \fn PIMapIterator PIMap::makeIterator() const
* \brief Returns PIMapIterator for this map
* \fn PIMapIterator PIMap::makeReverseIterator() const
* \brief Returns reverse PIMapIterator for this map
* \fn size_t PIMap::size() const
* \brief Returns entries count
* \fn int PIMap::size_s() const
* \brief Returns entries count
* \fn size_t PIMap::length() const
* \brief Returns entries count
* \fn bool PIMap::isEmpty() const
* \brief Returns if map is empty
* \fn T & PIMap::operator [](const Key & key)
* \brief Returns value for key "key". If there is no key in map, create one.
* \fn const T PIMap::operator [](const Key & key) const
* \brief Returns value for key "key". If there is no key in map, returns default T().
* \fn T & PIMap::at(const Key & key)
* \brief Equivalent to operator []
* \fn const T PIMap::at(const Key & key) const
* \brief Equivalent to operator []
* \fn PIMap & PIMap::operator <<(const PIMap & other)
* \brief Insert all etries of "other" to this map. Override existing values.
* \fn bool PIMap::operator ==(const PIMap & t) const
* \brief Compare operator
* \fn bool PIMap::operator !=(const PIMap & t) const
* \brief Compare operator
* \fn bool PIMap::contains(const Key & key) const
* \brief Returns "true" if map contains entry with key "key"
* \fn PIMap & PIMap::reserve(size_t new_size)
* \brief Reserve space for "new_size" entries
* \fn PIMap & PIMap::removeOne(const Key & key)
* \brief Remove entry with key "key"
* \fn PIMap & PIMap::remove(const Key & key)
* \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::erase(const Key & key)
* \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::clear()
* \brief Clear map
* \fn void PIMap::swap(PIMap & other)
* \brief Swap map with "other"
* \fn PIMap & PIMap::insert(const Key & key, const T & value)
* \brief Insert or rewrite entry with key "key" and value "value"
* \fn const T PIMap::value(const Key & key, const T & default = T())
* \brief Returns value for key "key". If there is no key in map, returns "default".
* \fn PIVector<T> PIMap::values() const
* \brief Returns all values as PIVector
* \fn Key PIMap::key(const T & value, const Key & default = Key()) const
* \brief Returns key for first founded value "value". If there is no such value in map, returns "default".
* \fn PIVector<Key> PIMap::keys() const
* \brief Returns all keys as PIVector
* */
/** \class PIMapIterator
* \brief Helper class to iterate over PIMap
* \details This class used to access keys and values in PIMap.
* You can use constructor to create iterator, or use \a PIMap::makeIterator()
* and \a PIMap::makeReverseIterator() methods.
*
* First usage variant:
* \code
* PIMap<int, PIString> m;
* m[1] = "one";
* m[2] = "two";
* m[4] = "four";
*
* auto it = m.makeIterator();
* while (it.next()) {
* piCout << it.key() << it.value();
* }
* // 1 one
* // 2 two
* // 4 four
* \endcode
*
* Using hasNext():
* \code
* while (it.hasNext()) {
* it.next();
* \endcode
*
* Using constructor:
* \code
* PIMapIterator<int, PIString> it(m);
* \endcode
*
* Write access:
* \code
* while (it.next()) {
* it.valueRef().append("_!");
* piCout << it.key() << it.value();
* }
*
* // 1 one_!
* // 2 two_!
* // 4 four_!
* \endcode
*
* Reverse iterator:
* \code
* auto it = m.makeReverseIterator();
* while (it.next()) {
* piCout << it.key() << it.value();
* }
*
* // 4 four
* // 2 two
* // 1 one
* \endcode
* \fn PIMapIterator(const PIMap & map, bool reverse = false)
* \brief Contructs iterator for "map". Current position is invalid.
* \fn const Key & PIMapIterator::key() const
* \brief Returns current entry key
* \fn const T & PIMapIterator::value() const
* \brief Returns current entry value
* \fn T & PIMapIterator::valueRef() const
* \brief Returns reference to current entry value
* \fn bool PIMapIterator::hasNext()
* \brief Returns if iterator can jump to next entry
* \fn bool PIMapIterator::next()
* \brief Jump to next entry and return if new position is valid.
* */

View File

@@ -67,10 +67,16 @@ void piQuickSort(T * a, ssize_t N) {
}
}
template <typename Key, typename T>
class PIMapIterator;
template <typename Key, typename T>
class PIMap {
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend class PIMapIterator;
public:
PIMap() {;}
PIMap(const PIMap<Key, T> & other) {*this = other;}
@@ -183,6 +189,9 @@ public:
const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}
PIMapIterator<Key, T> makeIterator() const {return PIMapIterator<Key, T>(*this);}
PIMapIterator<Key, T> makeReverseIterator() const {return PIMapIterator<Key, T>(*this, true);}
size_t size() const {return pim_content.size();}
int size_s() const {return pim_content.size_s();}
size_t length() const {return pim_content.size();}
@@ -327,6 +336,41 @@ protected:
};
template <typename Key, typename T>
class PIMapIterator {
typedef PIMap<Key, T> MapType;
public:
PIMapIterator(const PIMap<Key, T> & map, bool reverse = false): m(map), pos(-1), rev(reverse) {
if (rev) pos = m.size_s();
}
const Key & key() const {return const_cast<MapType & >(m)._key(pos);}
const T & value() const {return const_cast<MapType & >(m)._value(pos);}
T & valueRef() const {return const_cast<MapType & >(m)._value(pos);}
inline bool hasNext() const {
if (rev) {
return pos > 0;
} else {
return pos < (m.size_s() - 1);
}
return false;
}
inline bool next() {
if (rev) {
--pos;
return pos >= 0;
} else {
++pos;
return pos < m.size_s();
}
return false;
}
private:
const MapType & m;
ssize_t pos;
bool rev;
};
#ifdef PIP_STD_IOSTREAM
template<typename Key, typename Type>
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {

View File

@@ -56,6 +56,10 @@ public:
//! Constructs an empty byte array
PIByteArray() {;}
PIByteArray(const PIByteArray & o): PIDeque<uchar>(o) {}
PIByteArray(PIByteArray && o): PIDeque<uchar>(std::move(o)) {}
//! Constructs 0-filled byte array with size "size"
PIByteArray(const uint size) {resize(size);}
@@ -124,6 +128,10 @@ public:
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
PIByteArray & operator =(const PIByteArray & o) {if (this == &o) return *this; clear(); append(o); return *this;}
PIByteArray & operator =(PIByteArray && o) {swap(o); return *this;}
static PIByteArray fromUserInput(PIString str);
static PIByteArray fromHex(PIString str);
static PIByteArray fromBase64(const PIByteArray & base64);

View File

@@ -54,12 +54,18 @@ public:
int id;
T data;
};
template <typename T>
struct ChunkConst {
ChunkConst(int i, const T & d): id(i), data(d) {}
int id;
const T & data;
};
//! Returns chunk with ID "id" and value "data" for write to stream
template <typename T> static Chunk<T> chunk(int id, const T & data) {return Chunk<T>(id, data);}
template <typename T> static ChunkConst<T> chunk(int id, const T & data) {return ChunkConst<T>(id, data);}
//! Add data to this chunk strean with ID "id" and value "data"
template <typename T> PIChunkStream & add(int id, const T & data) {*this << Chunk<T>(id, data); return *this;}
template <typename T> PIChunkStream & add(int id, const T & data) {*this << ChunkConst<T>(id, data); return *this;}
void setSource(const PIByteArray & data);
void setSource(PIByteArray * data);
@@ -112,6 +118,7 @@ private:
PIMap<int, PIByteArray> data_map;
template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c);
template <typename T> friend PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::ChunkConst<T> & c);
};
template <typename T>
@@ -133,5 +140,24 @@ PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::Chunk<T> & c
}
return s;
}
template <typename T>
PIChunkStream & operator <<(PIChunkStream & s, const PIChunkStream::ChunkConst<T> & c) {
PIByteArray ba;
ba << c.data;
switch (s.version_) {
case PIChunkStream::Version_1:
(*(s.data_)) << c.id << ba;
break;
case PIChunkStream::Version_2:
if (s.data_->isEmpty())
(*(s.data_)) << uchar(uchar(s.version_) | 0x80);
PIChunkStream::writeVInt(*(s.data_), c.id);
PIChunkStream::writeVInt(*(s.data_), ba.size());
s.data_->append(ba);
break;
default: break;
}
return s;
}
#endif // PICHUNKSTREAM_H

View File

@@ -658,6 +658,26 @@ PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
}
PIString & PIString::replaceAll(const PIString & what, const char with) {
if (what.isEmpty()) return *this;
int l = what.length(), dl = what.length() - 1;
for (int i = 0; i < length() - l + 1; ++i) {
bool match = true;
for (int j = 0; j < l; ++j) {
if (at(j + i) != what[j]) {
match = false;
break;
}
}
if (!match) continue;
if (dl > 0) PIDeque<PIChar>::remove(i, dl);
at(i) = PIChar(with);
//i -= l;
}
return *this;
}
PIString & PIString::replaceAll(const char what, const char with) {
int l = length();
for (int i = 0; i < l; ++i) {

View File

@@ -283,6 +283,11 @@ public:
* \sa \a replace(), \a replaced() */
PIString & replaceAll(const PIString & what, const PIString & with);
/*! \brief Replace all founded substrings "what" with symbol "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replaceAll
* \sa \a replace(), \a replaced() */
PIString & replaceAll(const PIString & what, const char with);
/*! \brief Replace all founded symbols "what" with symbol "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replaceAll
* \sa \a replace(), \a replaced() */

View File

@@ -214,9 +214,10 @@ PIByteArray PIIntrospection::packThreads() {
if (p) {
p->mutex.lock();
PIMap<PIThread*, PIIntrospectionThreads::ThreadInfo> & tm(p->threads);
for (PIMap<PIThread*, PIIntrospectionThreads::ThreadInfo>::iterator i = tm.begin(); i != tm.end(); ++i) {
i.value().classname = PIStringAscii(i.key()->className());
i.value().name = i.key()->name();
auto it = tm.makeIterator();
while (it.next()) {
it.valueRef().classname = PIStringAscii(it.key()->className());
it.valueRef().name = it.key()->name();
}
ret << tm.values();
p->mutex.unlock();

View File

@@ -235,7 +235,7 @@ PIByteArray PIFile::readAll(bool forceRead) {
llong s = size();
if (s < 0) return a;
a.resize(s);
s = readAll(a.data());
fread(a.data(), 1, s, PRIVATE->fd);
seek(cp);
if (s >= 0) a.resize(s);
return a;

View File

@@ -388,8 +388,9 @@ bool PIConnection::removeDevice(const PIString & full_path) {
}
bounded_extractors.remove(dev);
channels_.remove(dev);
for (auto it = channels_.begin(); it != channels_.end(); it++)
it.value().removeAll(dev);
auto it = channels_.makeIterator();
while (it.next())
it.valueRef().removeAll(dev);
__device_pool__->lock();
if (diags_.value(dev, 0) != 0)
delete diags_.value(dev);
@@ -411,8 +412,9 @@ void PIConnection::removeAllDevices() {
s.value()->unlock();
}
channels_.remove(d);
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
it.value().removeAll(d);
auto it = channels_.makeIterator();
while (it.next())
it.valueRef().removeAll(d);
if (diags_.value(d, 0) != 0)
delete diags_.value(d);
diags_.remove(d);
@@ -566,8 +568,9 @@ void PIConnection::removeAllFilters() {
for (auto i = extractors.constBegin(); i != extractors.constEnd(); i++) {
if (i.value() == 0) continue;
channels_.remove(i.value()->extractor);
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
it.value().removeAll(i.value()->extractor);
auto it = channels_.makeIterator();
while (it.next())
it.valueRef().removeAll(i.value()->extractor);
if (diags_.value(i.value()->extractor, 0) != 0)
delete diags_.value(i.value()->extractor);
diags_.remove(i.value()->extractor);
@@ -658,8 +661,9 @@ bool PIConnection::removeChannel(const PIString & name0) {
if (pe0 != 0) dev0 = pe0;
if (dev0 == 0) return false;
channels_.remove(dev0);
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
it.value().removeAll(dev0);
auto it = channels_.makeIterator();
while (it.next())
it.valueRef().removeAll(dev0);
return true;
}
@@ -1240,8 +1244,9 @@ void PIConnection::Sender::tick(void * , int) {
void PIConnection::unboundExtractor(PIPacketExtractor * pe) {
if (pe == 0) return;
channels_.remove(pe);
for (PIMap<PIIODevice * , PIVector<PIIODevice * > >::iterator it = channels_.begin(); it != channels_.end(); ++it)
it.value().removeAll(pe);
auto it = channels_.makeIterator();
while (it.next())
it.valueRef().removeAll(pe);
bounded_extractors.remove(pe);
PIVector<PIIODevice * > k = bounded_extractors.keys();
piForeach (PIIODevice * i, k) {

View File

@@ -36,13 +36,12 @@ PIByteArray PIResources::get(const PIString & name) {
void PIResources::dump() {
PIMap<PIString, PIResourcesStorage::Section * > & sm(PIResourcesStorage::instance()->sections);
PIMap<PIString, PIResourcesStorage::Section * >::iterator si;
for (si = sm.begin(); si != sm.end(); ++si) {
auto si = PIResourcesStorage::instance()->sections.makeIterator();
while (si.next()) {
piCout << "Section [" << si.key() << "]";
if (!si.value()) continue;
PIMap<PIString, PIByteArray * >::iterator fi;
for (fi = si.value()->entries.begin(); fi != si.value()->entries.end(); ++fi) {
auto fi = si.value()->entries.makeIterator();
while (fi.next()) {
PIString s = fi.key() + ": ";
s << (fi.value() ? fi.value()->size_s() : 0) << " b";
piCout << " " << s;

View File

@@ -31,8 +31,8 @@ PIResourcesStorage::Section::~Section() {
void PIResourcesStorage::Section::add(const PIResourcesStorage::Section & s) {
PIMap<PIString, PIByteArray * >::const_iterator i;
for (i = s.entries.begin(); i != s.entries.end(); ++i) {
auto i = s.entries.makeIterator();
while (i.next()) {
if (!i.value()) continue;
if (entries.value(i.key(), 0)) continue;
entries[i.key()] = i.value();
@@ -83,10 +83,10 @@ void PIResourcesStorage::registerSection(const uchar * rc_data, const uchar * rc
piForeachC (PIResourcesStorage::__RCEntry & e, el) {
ebs[e.section] << e;
}
PIMap<PIString, PIVector<PIResourcesStorage::__RCEntry> >::iterator it;
for (it = ebs.begin(); it != ebs.end(); ++it) {
auto it = ebs.makeIterator();
while (it.next()) {
PIResourcesStorage::Section s;
PIVector<PIResourcesStorage::__RCEntry> & itv(it.value());
const PIVector<PIResourcesStorage::__RCEntry> & itv(it.value());
piForeachC (PIResourcesStorage::__RCEntry & e, itv) {
//piCout << "add" << e.name << e.alias << PIString::readableSize(e.size);
PIByteArray * eba = new PIByteArray(&(rc_data[e.offset]), e.size);
@@ -114,8 +114,8 @@ PIByteArray PIResourcesStorage::get(const PIString & section_name, const PIStrin
PIByteArray PIResourcesStorage::get(const PIString & entry_name) const {
PIMap<PIString, Section * >::const_iterator i;
for (i = sections.begin(); i != sections.end(); ++i) {
auto i = sections.makeIterator();
while (i.next()) {
if (!i.value()) continue;
PIByteArray * ba = i.value()->entries.value(entry_name, 0);
if (!ba) continue;

View File

@@ -331,9 +331,10 @@ void PISystemMonitor::run() {
tstat.cpu_load_system = piClampf(tstat.cpu_load_system, 0.f, 100.f);
tstat.cpu_load_user = piClampf(tstat.cpu_load_user , 0.f, 100.f);
for (PIMap<llong, ThreadStats>::iterator i = cur_tm.begin(); i != cur_tm.end(); ++i) {
auto i = cur_tm.makeIterator();
while (i.next()) {
if (!last_tm.contains(i.key())) continue;
ThreadStats & ts_new(i.value());
ThreadStats & ts_new(i.valueRef());
ThreadStats & ts_old(last_tm[i.key()]);
ts_new.cpu_load_kernel = calcThreadUsage(ts_new.kernel_time, ts_old.kernel_time);
ts_new.cpu_load_user = calcThreadUsage(ts_new.user_time, ts_old.user_time);

View File

@@ -20,43 +20,43 @@
#ifndef PIBLOCKINGDEQUEUE_H
#define PIBLOCKINGDEQUEUE_H
#include "pideque.h"
#include <queue>
#include "piconditionvar.h"
/**
* @brief A Queue that supports operations that wait for the queue to become non-empty when retrieving an element, and
* wait for space to become available in the queue when storing an element.
*/
template <typename T>
class PIBlockingDequeue: private PIDeque<T> {
template <typename T, template<typename = T, typename...> class Queue_ = std::deque, typename ConditionVariable_ = PIConditionVariable>
class PIBlockingDequeue {
public:
typedef Queue_<T> QueueType;
/**
* @brief Constructor
*/
explicit inline PIBlockingDequeue(size_t capacity = SIZE_MAX,
PIConditionVariable* cond_var_add = new PIConditionVariable(),
PIConditionVariable* cond_var_rem = new PIConditionVariable())
: cond_var_add(cond_var_add), cond_var_rem(cond_var_rem), max_size(capacity) { }
explicit PIBlockingDequeue(size_t capacity = SIZE_MAX)
: cond_var_add(new ConditionVariable_()), cond_var_rem(new ConditionVariable_()), max_size(capacity) { }
/**
* @brief Copy constructor. Initialize queue with copy of other queue elements. Not thread-safe for other queue.
* @brief Copy constructor. Initialize queue with copy of other container elements. Not thread-safe for other queue.
*/
explicit inline PIBlockingDequeue(const PIDeque<T>& other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
template<typename Iterable,
typename std::enable_if<!std::is_arithmetic<Iterable>::value, int>::type = 0>
explicit PIBlockingDequeue(const Iterable& other): PIBlockingDequeue() {
mutex.lock();
max_size = SIZE_MAX;
PIDeque<T>::append(other);
for (const T& t : other) data_queue.push_back(t);
mutex.unlock();
}
/**
* @brief Thread-safe copy constructor. Initialize queue with copy of other queue elements.
*/
inline PIBlockingDequeue(PIBlockingDequeue<T> & other) : cond_var_add(new PIConditionVariable()), cond_var_rem(new PIConditionVariable()) {
explicit PIBlockingDequeue(PIBlockingDequeue<T>& other): PIBlockingDequeue() {
other.mutex.lock();
mutex.lock();
max_size = other.max_size;
PIDeque<T>::append(static_cast<PIDeque<T>&>(other));
data_queue = other.data_queue;
mutex.unlock();
other.mutex.unlock();
}
@@ -71,10 +71,11 @@ public:
*
* @param v the element to add
*/
void put(const T & v) {
template<typename Type>
void put(Type && v) {
mutex.lock();
cond_var_rem->wait(mutex, [&]() { return PIDeque<T>::size() < max_size; });
PIDeque<T>::push_back(v);
cond_var_rem->wait(mutex, [&]() { return data_queue.size() < max_size; });
data_queue.push_back(std::forward<Type>(v));
mutex.unlock();
cond_var_add->notifyOne();
}
@@ -86,13 +87,14 @@ public:
* @param v the element to add
* @return true if the element was added to this queue, else false
*/
bool offer(const T & v) {
template<typename Type>
bool offer(Type && v) {
mutex.lock();
if (PIDeque<T>::size() >= max_size) {
if (data_queue.size() >= max_size) {
mutex.unlock();
return false;
}
PIDeque<T>::push_back(v);
data_queue.push_back(std::forward<Type>(v));
mutex.unlock();
cond_var_add->notifyOne();
return true;
@@ -106,10 +108,11 @@ public:
* @param timeoutMs how long to wait before giving up, in milliseconds
* @return true if successful, or false if the specified waiting time elapses before space is available
*/
bool offer(const T & v, int timeoutMs) {
template<typename Type>
bool offer(Type && v, int timeoutMs) {
mutex.lock();
bool isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return PIDeque<T>::size() < max_size; } );
if (isOk) PIDeque<T>::push_back(v);
bool isOk = cond_var_rem->waitFor(mutex, timeoutMs, [&]() { return data_queue.size() < max_size; } );
if (isOk) data_queue.push_back(std::forward<Type>(v));
mutex.unlock();
if (isOk) cond_var_add->notifyOne();
return isOk;
@@ -121,10 +124,10 @@ public:
* @return the head of this queue
*/
T take() {
T t;
mutex.lock();
cond_var_add->wait(mutex, [&]() { return !PIDeque<T>::isEmpty(); });
t = T(PIDeque<T>::take_front());
cond_var_add->wait(mutex, [&]() { return data_queue.size() != 0; });
T t = std::move(data_queue.front());
data_queue.pop_front();
mutex.unlock();
cond_var_rem->notifyOne();
return t;
@@ -140,11 +143,17 @@ public:
* return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/
T poll(int timeoutMs, const T & defaultVal = T(), bool * isOk = nullptr) {
T t;
template<typename Type = T>
T poll(int timeoutMs, Type && defaultVal = Type(), bool * isOk = nullptr) {
mutex.lock();
bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return !PIDeque<T>::isEmpty(); });
t = isNotEmpty ? T(PIDeque<T>::take_front()) : defaultVal;
bool isNotEmpty = cond_var_add->waitFor(mutex, timeoutMs, [&]() { return data_queue.size() != 0; });
T t;
if (isNotEmpty) {
t = std::move(data_queue.front());
data_queue.pop_front();
} else {
t = std::forward<Type>(defaultVal);
}
mutex.unlock();
if (isNotEmpty) cond_var_rem->notifyOne();
if (isOk) *isOk = isNotEmpty;
@@ -160,11 +169,17 @@ public:
* return value is retrieved value
* @return the head of this queue, or defaultVal if the specified waiting time elapses before an element is available
*/
T poll(const T & defaultVal = T(), bool * isOk = nullptr) {
template<typename Type = T>
T poll(Type && defaultVal = Type(), bool * isOk = nullptr) {
T t;
mutex.lock();
bool isNotEmpty = !PIDeque<T>::isEmpty();
t = isNotEmpty ? PIDeque<T>::take_front() : defaultVal;
bool isNotEmpty = data_queue.size() != 0;
if (isNotEmpty) {
t = std::move(data_queue.front());
data_queue.pop_front();
} else {
t = std::forward<Type>(defaultVal);
}
mutex.unlock();
if (isNotEmpty) cond_var_rem->notifyOne();
if (isOk) *isOk = isNotEmpty;
@@ -193,7 +208,7 @@ public:
*/
size_t remainingCapacity() {
mutex.lock();
size_t c = max_size - PIDeque<T>::size();
size_t c = max_size - data_queue.size();
mutex.unlock();
return c;
}
@@ -203,7 +218,7 @@ public:
*/
size_t size() {
mutex.lock();
size_t s = PIDeque<T>::size();
size_t s = data_queue.size();
mutex.unlock();
return s;
}
@@ -211,10 +226,14 @@ public:
/**
* @brief Removes all available elements from this queue and adds them to other given queue.
*/
size_t drainTo(PIDeque<T>& other, size_t maxCount = SIZE_MAX) {
template<typename Appendable>
size_t drainTo(Appendable& other, size_t maxCount = SIZE_MAX) {
mutex.lock();
size_t count = ((maxCount > PIDeque<T>::size()) ? PIDeque<T>::size() : maxCount);
for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front());
size_t count = maxCount > data_queue.size() ? data_queue.size() : maxCount;
for (size_t i = 0; i < count; ++i) {
other.push_back(std::move(data_queue.front()));
data_queue.pop_front();
}
mutex.unlock();
return count;
}
@@ -225,18 +244,23 @@ public:
size_t drainTo(PIBlockingDequeue<T>& other, size_t maxCount = SIZE_MAX) {
mutex.lock();
other.mutex.lock();
size_t count = maxCount > PIDeque<T>::size() ? PIDeque<T>::size() : maxCount;
size_t otherRemainingCapacity = other.max_size - static_cast<PIDeque<T> >(other).size();
size_t count = maxCount > data_queue.size() ? data_queue.size() : maxCount;
size_t otherRemainingCapacity = other.max_size - data_queue.size();
if (count > otherRemainingCapacity) count = otherRemainingCapacity;
for (size_t i = 0; i < count; ++i) other.push_back(PIDeque<T>::take_front());
for (size_t i = 0; i < count; ++i) {
other.data_queue.push_back(std::move(data_queue.front()));
data_queue.pop_front();
}
other.mutex.unlock();
mutex.unlock();
return count;
}
private:
protected:
PIMutex mutex;
PIConditionVariable * cond_var_add, * cond_var_rem;
// TODO change to type without point
ConditionVariable_ *cond_var_add, *cond_var_rem;
QueueType data_queue;
size_t max_size;
};

View File

View File

@@ -0,0 +1,200 @@
/*
PIP - Platform Independent Primitives
Stephan Fomenko
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 PIEXECUTOR_H
#define PIEXECUTOR_H
#include "piblockingdequeue.h"
#include <atomic>
#include <future>
/**
* @brief Wrapper for custom invoke operator available function types.
* @note Source from: "Энтони Уильямс, Параллельное программирование на С++ в действии. Практика разработки многопоточных
* программ. Пер. с англ. Слинкин А. А. - M.: ДМК Пресс, 2012 - 672c.: ил." (page 387)
*/
class FunctionWrapper {
struct ImplBase {
virtual void call() = 0;
virtual ~ImplBase() = default;
};
std::unique_ptr<ImplBase> impl;
template<typename F>
struct ImplType: ImplBase {
F f;
explicit ImplType(F&& f): f(std::forward<F>(f)) {}
void call() final { f(); }
};
public:
template<typename F, typename = std::enable_if<!std::is_same<F, FunctionWrapper>::value> >
explicit FunctionWrapper(F&& f): impl(new ImplType<F>(std::forward<F>(f))) {}
void operator()() { impl->call(); }
explicit operator bool() const noexcept { return static_cast<bool>(impl); }
FunctionWrapper() = default;
FunctionWrapper(FunctionWrapper&& other) noexcept : impl(std::move(other.impl)) {}
FunctionWrapper& operator=(FunctionWrapper&& other) noexcept {
impl = std::move(other.impl);
return *this;
}
FunctionWrapper(const FunctionWrapper& other) = delete;
FunctionWrapper& operator=(const FunctionWrapper&) = delete;
};
template <typename Thread_ = PIThread, typename Dequeue_ = PIBlockingDequeue<FunctionWrapper>>
class PIThreadPoolExecutorTemplate {
public:
NO_COPY_CLASS(PIThreadPoolExecutorTemplate)
explicit PIThreadPoolExecutorTemplate(size_t corePoolSize = 1) : isShutdown_(false) { makePool(corePoolSize); }
virtual ~PIThreadPoolExecutorTemplate() {
shutdownNow();
while (threadPool.size() > 0) delete threadPool.take_back();
}
template<typename FunctionType>
std::future<typename std::result_of<FunctionType()>::type> submit(FunctionType&& callable) {
typedef typename std::result_of<FunctionType()>::type ResultType;
if (!isShutdown_) {
std::packaged_task<ResultType()> callable_task(std::forward<FunctionType>(callable));
auto future = callable_task.get_future();
FunctionWrapper functionWrapper(callable_task);
taskQueue.offer(std::move(functionWrapper));
return future;
} else {
return std::future<ResultType>();
}
}
template<typename FunctionType>
void execute(FunctionType&& runnable) {
if (!isShutdown_) {
FunctionWrapper function_wrapper(std::forward<FunctionType>(runnable));
taskQueue.offer(std::move(function_wrapper));
}
}
void shutdown() {
isShutdown_ = true;
}
void shutdownNow() {
isShutdown_ = true;
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
}
bool isShutdown() const {
return isShutdown_;
}
bool awaitTermination(int timeoutMs) {
PITimeMeasurer measurer;
for (size_t i = 0; i < threadPool.size(); ++i) {
int dif = timeoutMs - (int)measurer.elapsed_m();
if (dif < 0) return false;
if (!threadPool[i]->waitForFinish(dif)) return false;
}
return true;
}
protected:
std::atomic_bool isShutdown_;
Dequeue_ taskQueue;
PIVector<Thread_*> threadPool;
template<typename Function>
PIThreadPoolExecutorTemplate(size_t corePoolSize, Function&& onBeforeStart) : isShutdown_(false) {
makePool(corePoolSize, std::forward<Function>(onBeforeStart));
}
void makePool(size_t corePoolSize, std::function<void(Thread_*)>&& onBeforeStart = [](Thread_*){}) {
for (size_t i = 0; i < corePoolSize; ++i) {
auto* thread = new Thread_([&, i](){
auto runnable = taskQueue.poll(100);
if (runnable) {
runnable();
}
if (isShutdown_ && taskQueue.size() == 0) threadPool[i]->stop();
});
threadPool.push_back(thread);
onBeforeStart(thread);
thread->start();
}
}
};
typedef PIThreadPoolExecutorTemplate<> PIThreadPoolExecutor;
#ifdef DOXYGEN
/**
* @brief Thread pools address two different problems: they usually provide improved performance when executing large
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
* managing the resources, including threads, consumed when executing a collection of tasks.
*/
class PIThreadPoolExecutor {
public:
explicit PIThreadPoolExecutor(size_t corePoolSize);
virtual ~PIThreadPoolExecutor();
/**
* @brief Submits a Runnable task for execution and returns a Future representing that task. The Future's get method
* will return null upon successful completion.
*
* @tparam FunctionType - custom type of function with operator() and return type
* @tparam R - derived from FunctionType return type
*
* @param callable - the task to submit
* @return a future representing pending completion of the task
*/
std::future<R> submit(FunctionType&& callable);
/**
* @brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task
* cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been
* reached.
*
* @tparam FunctionType - custom type of function with operator() and return type
*
* @param runnable not empty function for thread pool execution
*/
void execute(FunctionType&& runnable);
/**
* @brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be
* accepted. Invocation has no additional effect if already shut down. This method does not wait for previously
* submitted tasks to complete execution. Use awaitTermination to do that.
*/
void shutdown();
void shutdownNow();
bool isShutdown() const;
bool awaitTermination(int timeoutMs);
};
#endif //DOXYGEN
#endif //PIEXECUTOR_H

View File

@@ -25,7 +25,7 @@
#include "pitimer.h"
#include "pipipelinethread.h"
#include "pigrabberbase.h"
#include "pithreadpoolexecutor.h"
#include "piexecutor.h"
#include "piconditionvar.h"
#endif // PITHREADMODULE_H

View File

@@ -1,89 +0,0 @@
/*
PIP - Platform Independent Primitives
Stephan Fomenko
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 "pithreadpoolexecutor.h"
#include "pisysteminfo.h"
/*! \class PIThreadPoolExecutor
* @brief Thread pools address two different problems: they usually provide improved performance when executing large
* numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and
* managing the resources, including threads, consumed when executing a collection of tasks.
*/
PIThreadPoolExecutor::PIThreadPoolExecutor(size_t corePoolSize, PIBlockingDequeue<std::function<void()> > * taskQueue_) : isShutdown_(false) {
queue_own = false;
if (corePoolSize <= 0)
corePoolSize = PISystemInfo::instance()->processorsCount;
if (!taskQueue_) {
taskQueue = new PIBlockingDequeue<std::function<void()> >();
queue_own = true;
}
for (size_t i = 0; i < corePoolSize; ++i) {
PIThread * thread = new PIThread([&, i](){
auto runnable = taskQueue->poll(100, std::function<void()>());
if (runnable) {
runnable();
}
if (isShutdown_ && taskQueue->size() == 0) threadPool[i]->stop();
});
threadPool.push_back(thread);
thread->start();
}
}
bool PIThreadPoolExecutor::awaitTermination(int timeoutMs) {
PITimeMeasurer measurer;
for (size_t i = 0; i < threadPool.size(); ++i) {
int dif = timeoutMs - (int)measurer.elapsed_m();
if (dif < 0) return false;
if (!threadPool[i]->waitForFinish(dif)) return false;
}
return true;
}
void PIThreadPoolExecutor::shutdownNow() {
isShutdown_ = true;
for (size_t i = 0; i < threadPool.size(); ++i) threadPool[i]->stop();
}
PIThreadPoolExecutor::~PIThreadPoolExecutor() {
shutdownNow();
while (threadPool.size() > 0) delete threadPool.take_back();
if (queue_own)
delete taskQueue;
}
void PIThreadPoolExecutor::execute(const std::function<void()> & runnable) {
if (!isShutdown_) taskQueue->offer(runnable);
}
bool PIThreadPoolExecutor::isShutdown() const {
return isShutdown_;
}
void PIThreadPoolExecutor::shutdown() {
isShutdown_ = true;
}

View File

@@ -1,63 +0,0 @@
/*
PIP - Platform Independent Primitives
Stephan Fomenko
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 PITHREADPOOLEXECUTOR_H
#define PITHREADPOOLEXECUTOR_H
#include "piblockingdequeue.h"
#include <atomic>
class PIP_EXPORT PIThreadPoolExecutor {
public:
explicit PIThreadPoolExecutor(size_t corePoolSize = -1, PIBlockingDequeue<std::function<void()> > * taskQueue_ = 0);
virtual ~PIThreadPoolExecutor();
/**
* @brief Executes the given task sometime in the future. The task execute in an existing pooled thread. If the task
* cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been
* reached.
*
* @param runnable not empty function for thread pool execution
*/
void execute(const std::function<void()> & runnable);
void shutdownNow();
/**
* @brief Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be
* accepted. Invocation has no additional effect if already shut down. This method does not wait for previously
* submitted tasks to complete execution. Use awaitTermination to do that.
*/
void shutdown();
bool isShutdown() const;
bool awaitTermination(int timeoutMs);
private:
std::atomic_bool isShutdown_;
PIBlockingDequeue<std::function<void()> > * taskQueue;
PIVector<PIThread*> threadPool;
bool queue_own;
};
#endif // PITHREADPOOLEXECUTOR_H

View File

@@ -34,32 +34,81 @@ int main() {
class db {
public:
db() {
name = PIStringAscii("sflner;ljner.vjnrevsg;j35m4;gberjg2mnv");
for (int i=0; i<10000; ++i)
x << sin(double(i)/180.0);
//printf("jkfkhg\n");
}
private:
PIString name;
PIVector<double> x;
};
inline PIByteArray & operator <<(PIByteArray & ba, const db & v) {
PIChunkStream cs;
cs.add(1, v.name).add(2, v.x);
ba << cs.data();
return ba;
}
inline PIByteArray & operator >>(PIByteArray & ba, db & v) {
PIByteArray src; ba >> src; PIChunkStream cs(src);
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: cs.get(v.name); break;
case 2: cs.get(v.x); break;
}
}
return ba;
}
PIEthernet eth;
#include "picodeparser.h"
int main() {
/*PIString s(" 324 654 sf 5fdwg sdfsdf sdfefg");
piCout << s;
piCout << s.replaceAll(' ', '1');*/
piDebug = false;
//PICodeParser cp;
//cp.parseFile("SH_plugin_base.h");
PIMap<int, PIString> m;
m[1] = "one";
m[2] = "two";
auto it = m.makeIterator();
while (it.next()) {
//it.next();
it.valueRef() << "_!";
piCout << it.key() << it.value();
}
/*eth.__meta_data
piForeachC (auto & i, cp.enums) {
i.
}*/
/*piDebug = false;
double min = -1, max = -1, mean = 0;
for (int i = 0; i < 1; ++i) {
PICodeParser cp;
const int iterations = 50;
db d, d2;
for (int i = 0; i < iterations; ++i) {
//PICodeParser cp;
PITimeMeasurer tm;
cp.parseFile("SH_plugin_base.h");
for (int j = 0; j < 100; ++j) {
PIByteArray ba;
ba << d;
}
//cp.parseFile("SH_plugin_base.h");
double ms = tm.elapsed_m();
if (min < 0) min = ms;
if (max < 0) max = ms;
min = piMin(min, ms);
max = piMax(max, ms);
mean += ms;
PIByteArray ba;
ba << d;
d2.name.clear();
d2.x.clear();
ba >> d2;
}
piDebug = true;
piCout << min << (mean / 50) << max;
piCout << d2.name << d2.x.size_s();
piCout << min << (mean / iterations) << max;*/
}

View File

@@ -4,10 +4,12 @@ macro(pip_test NAME LIBS)
file(GLOB _CPPS "${NAME}/*.cpp")
file(GLOB _HDRS "${NAME}/*.h")
set(_target pip_${NAME}_test)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PIP_ROOT_BINARY_DIR}")
add_executable(${_target} ${_CPPS} ${_HDRS})
target_link_libraries(${_target} pip ${LIBS} gtest_main gmock_main)
add_test(NAME ${_target} COMMAND tests)
add_custom_target(${_target}_perform ALL COMMAND ${_target})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
list(APPEND PIP_TESTS_LIST "${NAME}")
set(PIP_TESTS_LIST ${PIP_TESTS_LIST} PARENT_SCOPE)
endmacro()

View File

@@ -1,110 +1,363 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "testutil.h"
#include "piblockingdequeue.h"
class MockConditionVar: public PIConditionVariable {
using ::testing::_;
using ::testing::Return;
using ::testing::Eq;
using ::testing::Ne;
using ::testing::Matcher;
using ::testing::Expectation;
using ::testing::Sequence;
using ::testing::NiceMock;
class MockConditionVar {
public:
bool isWaitCalled = false;
bool isWaitForCalled = false;
bool isTrueCondition = false;
int timeout = -1;
void wait(PIMutex& lk) override {
isWaitCalled = true;
}
void wait(PIMutex& lk, const std::function<bool()>& condition) override {
isWaitCalled = true;
lk.lock();
isTrueCondition = condition();
lk.unlock();
}
bool waitFor(PIMutex& lk, int timeoutMs) override {
isWaitForCalled = true;
timeout = timeoutMs;
return false;
}
bool waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()>& condition) override {
isWaitForCalled = true;
lk.lock();
isTrueCondition = condition();
timeout = timeoutMs;
lk.unlock();
return isTrueCondition;
}
MOCK_METHOD1(wait, void(PIMutex&));
MOCK_METHOD2(wait, void(PIMutex&, const std::function<bool()>&));
MOCK_METHOD2(waitFor, bool(PIMutex&, int));
MOCK_METHOD3(waitFor, bool(PIMutex&, int, const std::function<bool()>&));
MOCK_METHOD0(notifyOne, void());
};
TEST(BlockingDequeueUnitTest, put_is_block_when_capacity_reach) {
size_t capacity = 0;
auto conditionVarAdd = new MockConditionVar();
auto conditionVarRem = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVarAdd, conditionVarRem);
dequeue.put(11);
ASSERT_TRUE(conditionVarRem->isWaitCalled);
ASSERT_FALSE(conditionVarRem->isTrueCondition);
struct QueueElement {
bool is_empty;
int value;
int copy_count;
QueueElement(): is_empty(true), value(0), copy_count(0) { }
explicit QueueElement(int value): is_empty(false), value(value), copy_count(0) { }
QueueElement(const QueueElement& other) {
this->is_empty = other.is_empty;
this->value = other.value;
this->copy_count = 0;
const_cast<int&>(other.copy_count)++;
}
QueueElement(QueueElement&& other) noexcept : QueueElement() {
std::swap(is_empty, other.is_empty);
std::swap(value, other.value);
std::swap(copy_count, other.copy_count);
}
bool operator==(const QueueElement &rhs) const {
return is_empty == rhs.is_empty &&
value == rhs.value;
}
bool operator!=(const QueueElement &rhs) const {
return !(rhs == *this);
}
friend std::ostream& operator<<(std::ostream& os, const QueueElement& el) {
return os << "{ is_empty:" << el.is_empty << ", value:" << el.value << ", copy_count:" << el.copy_count << " }";
}
};
template<typename T>
class MockDequeBase {
public:
MOCK_METHOD1_T(push_back_rval, void(T));
MOCK_METHOD1_T(push_back, void(const T&));
MOCK_METHOD0(size, size_t());
MOCK_METHOD0_T(front, T());
MOCK_METHOD0(pop_front, void());
void push_back(T&& t) {
push_back_rval(t);
}
};
template<typename T>
class MockDeque: public NiceMock<MockDequeBase<T>> {};
class PIBlockingDequeuePrepare: public PIBlockingDequeue<QueueElement, MockDeque, NiceMock<MockConditionVar>> {
public:
typedef PIBlockingDequeue<QueueElement, MockDeque, NiceMock<MockConditionVar>> SuperClass;
explicit PIBlockingDequeuePrepare(size_t capacity = SIZE_MAX): SuperClass(capacity) { }
template<typename Iterable,
typename std::enable_if<!std::is_arithmetic<Iterable>::value, int>::type = 0>
explicit PIBlockingDequeuePrepare(const Iterable& other): SuperClass(other) { }
MockConditionVar* getCondVarAdd() { return this->cond_var_add; }
MockConditionVar* getCondVarRem() { return this->cond_var_rem; }
MockDeque<QueueElement>& getQueue() { return this->data_queue; }
size_t getMaxSize() { return max_size; }
};
class BlockingDequeueUnitTest: public ::testing::Test {
public:
int timeout = 100;
size_t capacity;
PIBlockingDequeuePrepare dequeue;
QueueElement element;
BlockingDequeueUnitTest(): capacity(1), dequeue(capacity), element(11) {}
void offer2_is_wait_predicate(bool isCapacityReach);
void put_is_wait_predicate(bool isCapacityReach);
void take_is_wait_predicate(bool isEmpty);
};
TEST_F(BlockingDequeueUnitTest, construct_default_is_max_size_eq_size_max) {
PIBlockingDequeuePrepare dequeue;
ASSERT_EQ(dequeue.getMaxSize(), SIZE_MAX);
}
TEST(BlockingDequeueUnitTest, offer_timedout_is_false_when_capacity_reach) {
size_t capacity = 0;
int timeout = 11;
auto conditionVarAdd = new MockConditionVar();
auto conditionVarRem = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVarAdd, conditionVarRem);
ASSERT_FALSE(dequeue.offer(11, timeout));
TEST_F(BlockingDequeueUnitTest, construct_from_constant_is_max_size_eq_capacity) {
PIBlockingDequeuePrepare dequeue(2);
ASSERT_EQ(dequeue.getMaxSize(), 2);
}
TEST(BlockingDequeueUnitTest, offer_timedout_is_block_when_capacity_reach) {
size_t capacity = 0;
int timeout = 11;
auto conditionVarAdd = new MockConditionVar();
auto conditionVarRem = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVarAdd, conditionVarRem);
dequeue.offer(11, timeout);
EXPECT_TRUE(conditionVarRem->isWaitForCalled);
EXPECT_EQ(timeout, conditionVarRem->timeout);
ASSERT_FALSE(conditionVarRem->isTrueCondition);
TEST_F(BlockingDequeueUnitTest, construct_from_capacity_is_max_size_eq_capacity) {
ASSERT_EQ(dequeue.getMaxSize(), capacity);
}
TEST(BlockingDequeueUnitTest, offer_is_true_before_capacity_reach) {
size_t capacity = 1;
PIBlockingDequeue<int> dequeue(capacity);
ASSERT_TRUE(dequeue.offer(10));
TEST_F(BlockingDequeueUnitTest, construct_from_iterable) {
std::vector<QueueElement> iterable;
iterable.emplace_back(11);
iterable.emplace_back(22);
PIBlockingDequeuePrepare dequeue(iterable);
}
TEST(BlockingDequeueUnitTest, offer_is_false_when_capacity_reach) {
size_t capacity = 1;
PIBlockingDequeue<int> dequeue(capacity);
dequeue.offer(11);
ASSERT_FALSE(dequeue.offer(10));
void BlockingDequeueUnitTest::put_is_wait_predicate(bool isCapacityReach) {
std::function<bool()> conditionVarPredicate;
EXPECT_CALL(*dequeue.getCondVarRem(), wait(_, _))
.WillOnce([&](PIMutex& m, const std::function<bool()>& predicate){ conditionVarPredicate = predicate; });
dequeue.put(element);
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(isCapacityReach ? capacity : capacity - 1));
ASSERT_EQ(conditionVarPredicate(), !isCapacityReach);
}
TEST_F(BlockingDequeueUnitTest, put_is_wait_predicate_true) {
put_is_wait_predicate(false);
}
TEST_F(BlockingDequeueUnitTest, put_is_wait_predicate_false_when_capacity_reach) {
put_is_wait_predicate(true);
}
TEST_F(BlockingDequeueUnitTest, put_is_insert_by_copy) {
EXPECT_CALL(dequeue.getQueue(), push_back( Eq(element) ))
.WillOnce(Return());
dequeue.put(element);
}
TEST_F(BlockingDequeueUnitTest, put_is_insert_by_move) {
QueueElement copyElement = element;
EXPECT_CALL(dequeue.getQueue(), push_back_rval( Eq(element) ))
.WillOnce(Return());
dequeue.put(std::move(copyElement));
}
TEST_F(BlockingDequeueUnitTest, put_is_notify_about_insert) {
EXPECT_CALL(*dequeue.getCondVarAdd(), notifyOne)
.WillOnce(Return());
dequeue.put(element);
}
TEST_F(BlockingDequeueUnitTest, offer1_is_insert_by_copy) {
EXPECT_CALL(dequeue.getQueue(), push_back( Eq(element) ))
.WillOnce(Return());
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(capacity - 1));
dequeue.offer(element);
}
TEST_F(BlockingDequeueUnitTest, offer1_is_insert_by_move) {
QueueElement copyElement = element;
EXPECT_CALL(dequeue.getQueue(), push_back_rval( Eq(element) ))
.WillOnce(Return());
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(capacity - 1));
dequeue.offer(std::move(copyElement));
}
TEST_F(BlockingDequeueUnitTest, offer1_is_not_insert_when_capacity_reach) {
EXPECT_CALL(dequeue.getQueue(), push_back(_))
.Times(0);
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(capacity));
dequeue.offer(element);
}
TEST_F(BlockingDequeueUnitTest, offer1_is_true_when_insert) {
ON_CALL(dequeue.getQueue(), push_back(_))
.WillByDefault(Return());
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(capacity - 1));
ASSERT_TRUE(dequeue.offer(element));
}
TEST_F(BlockingDequeueUnitTest, offer1_is_false_when_capacity_reach) {
ON_CALL(dequeue.getQueue(), push_back(_))
.WillByDefault(Return());
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(capacity));
ASSERT_FALSE(dequeue.offer(element));
}
TEST_F(BlockingDequeueUnitTest, offer1_is_notify_about_insert) {
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(capacity - 1));
EXPECT_CALL(*dequeue.getCondVarAdd(), notifyOne)
.WillOnce(Return());
dequeue.offer(element);
}
TEST_F(BlockingDequeueUnitTest, offer1_is_not_notify_about_insert_when_capacity_reach) {
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(capacity));
EXPECT_CALL(*dequeue.getCondVarAdd(), notifyOne)
.Times(0);
dequeue.offer(element);
}
void BlockingDequeueUnitTest::offer2_is_wait_predicate(bool isCapacityReach) {
std::function<bool()> conditionVarPredicate;
EXPECT_CALL(*dequeue.getCondVarRem(), waitFor(_, Eq(timeout), _))
.WillOnce([&](PIMutex& m, int timeout, const std::function<bool()>& predicate) {
conditionVarPredicate = predicate;
return isCapacityReach;
});
dequeue.offer(element, timeout);
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(isCapacityReach ? capacity : capacity - 1));
ASSERT_EQ(conditionVarPredicate(), !isCapacityReach);
}
TEST_F(BlockingDequeueUnitTest, offer2_is_wait_predicate_true) {
offer2_is_wait_predicate(false);
}
TEST_F(BlockingDequeueUnitTest, offer2_is_wait_predicate_false_when_capacity_reach) {
offer2_is_wait_predicate(true);
}
TEST_F(BlockingDequeueUnitTest, offer2_is_insert_by_copy) {
EXPECT_CALL(*dequeue.getCondVarRem(), waitFor(_, Eq(timeout), _))
.WillOnce(Return(true));
EXPECT_CALL(dequeue.getQueue(), push_back( Eq(element) ))
.WillOnce(Return());
dequeue.offer(element, timeout);
}
TEST_F(BlockingDequeueUnitTest, offer2_is_insert_by_move) {
QueueElement copyElement = element;
EXPECT_CALL(*dequeue.getCondVarRem(), waitFor(_, Eq(timeout), _))
.WillOnce(Return(true));
EXPECT_CALL(dequeue.getQueue(), push_back_rval( Eq(element) ))
.WillOnce(Return());
dequeue.offer(std::move(copyElement), timeout);
}
TEST_F(BlockingDequeueUnitTest, offer2_is_not_insert_when_timeout) {
EXPECT_CALL(*dequeue.getCondVarRem(), waitFor(_, Eq(timeout), _))
.WillOnce(Return(false));
EXPECT_CALL(dequeue.getQueue(), push_back(_))
.Times(0);
dequeue.offer(element, timeout);
}
TEST_F(BlockingDequeueUnitTest, offer2_is_true_when_insert) {
ON_CALL(*dequeue.getCondVarRem(), waitFor(_, _, _))
.WillByDefault(Return(true));
ASSERT_TRUE(dequeue.offer(element, timeout));
}
TEST_F(BlockingDequeueUnitTest, offer2_is_false_when_timeout) {
ON_CALL(*dequeue.getCondVarRem(), waitFor(_, _, _))
.WillByDefault(Return(false));
ASSERT_FALSE(dequeue.offer(element, timeout));
}
TEST_F(BlockingDequeueUnitTest, offer2_is_notify_about_insert) {
ON_CALL(*dequeue.getCondVarRem(), waitFor(_, _, _))
.WillByDefault(Return(true));
EXPECT_CALL(*dequeue.getCondVarAdd(), notifyOne)
.WillOnce(Return());
dequeue.offer(element, timeout);
}
TEST_F(BlockingDequeueUnitTest, offer2_is_not_notify_about_insert_when_timeout) {
ON_CALL(*dequeue.getCondVarRem(), waitFor(_, _, _))
.WillByDefault(Return(false));
EXPECT_CALL(*dequeue.getCondVarAdd(), notifyOne)
.Times(0);
dequeue.offer(element, timeout);
}
void BlockingDequeueUnitTest::take_is_wait_predicate(bool isEmpty) {
std::function<bool()> conditionVarPredicate;
EXPECT_CALL(*dequeue.getCondVarAdd(), wait(_, _))
.WillOnce([&](PIMutex& m, const std::function<bool()>& predicate) { conditionVarPredicate = predicate; });
dequeue.take();
ON_CALL(dequeue.getQueue(), size)
.WillByDefault(Return(isEmpty ? 0 : 1));
ASSERT_EQ(conditionVarPredicate(), !isEmpty);
}
TEST_F(BlockingDequeueUnitTest, take_is_wait_predicate_true) {
take_is_wait_predicate(false);
}
TEST_F(BlockingDequeueUnitTest, take_is_wait_predicate_false_when_queue_empty) {
take_is_wait_predicate(true);
}
TEST_F(BlockingDequeueUnitTest, take_is_get_and_remove) {
Expectation front = EXPECT_CALL(dequeue.getQueue(), front())
.WillOnce(Return(element));
EXPECT_CALL(dequeue.getQueue(), pop_front())
.After(front)
.WillOnce(Return());
QueueElement takenElement = dequeue.take();
ASSERT_EQ(element, takenElement);
}
TEST_F(BlockingDequeueUnitTest, take_is_notify_about_remove) {
EXPECT_CALL(*dequeue.getCondVarRem(), notifyOne)
.WillOnce(Return());
dequeue.take();
}
/*
// TODO change take_is_block_when_empty to prevent segfault
TEST(DISABLED_BlockingDequeueUnitTest, take_is_block_when_empty) {
size_t capacity = 1;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
// May cause segfault because take front of empty queue
dequeue.take();
EXPECT_TRUE(conditionVar->isWaitCalled);
ASSERT_FALSE(conditionVar->isTrueCondition);
EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitCalled);
ASSERT_FALSE(dequeue.getCondVarAdd()->isTrueCondition);
}
TEST(BlockingDequeueUnitTest, take_is_not_block_when_not_empty) {
size_t capacity = 1;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
dequeue.take();
EXPECT_TRUE(conditionVar->isWaitCalled);
ASSERT_TRUE(conditionVar->isTrueCondition);
EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitCalled);
ASSERT_TRUE(dequeue.getCondVarAdd()->isTrueCondition);
}
TEST(BlockingDequeueUnitTest, take_is_value_eq_to_offer_value) {
size_t capacity = 1;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
ASSERT_EQ(dequeue.take(), 111);
@@ -112,8 +365,7 @@ TEST(BlockingDequeueUnitTest, take_is_value_eq_to_offer_value) {
TEST(BlockingDequeueUnitTest, take_is_last) {
size_t capacity = 10;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
EXPECT_TRUE(dequeue.offer(111));
EXPECT_TRUE(dequeue.offer(222));
ASSERT_EQ(dequeue.take(), 111);
@@ -123,25 +375,22 @@ TEST(BlockingDequeueUnitTest, take_is_last) {
TEST(BlockingDequeueUnitTest, poll_is_not_block_when_empty) {
size_t capacity = 1;
bool isOk;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.poll(111, &isOk);
EXPECT_FALSE(conditionVar->isWaitForCalled);
EXPECT_FALSE(dequeue.getCondVarAdd()->isWaitForCalled);
}
TEST(BlockingDequeueUnitTest, poll_is_default_value_when_empty) {
size_t capacity = 1;
bool isOk;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
ASSERT_EQ(dequeue.poll(111, &isOk), 111);
}
TEST(BlockingDequeueUnitTest, poll_is_offer_value_when_not_empty) {
size_t capacity = 1;
bool isOk;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
ASSERT_EQ(dequeue.poll(-1, &isOk), 111);
}
@@ -149,47 +398,42 @@ TEST(BlockingDequeueUnitTest, poll_is_offer_value_when_not_empty) {
TEST(BlockingDequeueUnitTest, poll_timeouted_is_block_when_empty) {
size_t capacity = 1;
int timeout = 11;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.poll(timeout, 111);
EXPECT_TRUE(conditionVar->isWaitForCalled);
EXPECT_EQ(timeout, conditionVar->timeout);
ASSERT_FALSE(conditionVar->isTrueCondition);
EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitForCalled);
EXPECT_EQ(timeout, dequeue.getCondVarAdd()->timeout);
ASSERT_FALSE(dequeue.getCondVarAdd()->isTrueCondition);
}
TEST(BlockingDequeueUnitTest, poll_timeouted_is_default_value_when_empty) {
size_t capacity = 1;
int timeout = 11;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
ASSERT_EQ(dequeue.poll(timeout, 111), 111);
}
TEST(BlockingDequeueUnitTest, poll_timeouted_is_not_block_when_not_empty) {
size_t capacity = 1;
int timeout = 11;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
dequeue.poll(timeout, -1);
EXPECT_TRUE(conditionVar->isWaitForCalled);
ASSERT_TRUE(conditionVar->isTrueCondition);
EXPECT_TRUE(dequeue.getCondVarAdd()->isWaitForCalled);
ASSERT_TRUE(dequeue.getCondVarAdd()->isTrueCondition);
}
TEST(BlockingDequeueUnitTest, poll_timeouted_is_offer_value_when_not_empty) {
size_t capacity = 1;
int timeout = 11;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
ASSERT_EQ(dequeue.poll(timeout, -1), 111);
}
TEST(BlockingDequeueUnitTest, poll_timeouted_is_last) {
size_t capacity = 10;
auto conditionVar = new MockConditionVar();
PIBlockingDequeue<int> dequeue(capacity, conditionVar);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
dequeue.offer(222);
ASSERT_EQ(dequeue.poll(10, -1), 111);
@@ -198,13 +442,13 @@ TEST(BlockingDequeueUnitTest, poll_timeouted_is_last) {
TEST(BlockingDequeueUnitTest, capacity_is_eq_constructor_capacity) {
size_t capacity = 10;
PIBlockingDequeue<int> dequeue(capacity);
PIBlockingDequeuePrepare<int> dequeue(capacity);
ASSERT_EQ(dequeue.capacity(), capacity);
}
TEST(BlockingDequeueUnitTest, remainingCapacity_is_dif_of_capacity_and_size) {
size_t capacity = 2;
PIBlockingDequeue<int> dequeue(capacity);
PIBlockingDequeuePrepare<int> dequeue(capacity);
ASSERT_EQ(dequeue.remainingCapacity(), capacity);
dequeue.offer(111);
ASSERT_EQ(dequeue.remainingCapacity(), capacity - 1);
@@ -212,7 +456,7 @@ TEST(BlockingDequeueUnitTest, remainingCapacity_is_dif_of_capacity_and_size) {
TEST(BlockingDequeueUnitTest, remainingCapacity_is_zero_when_capacity_reach) {
size_t capacity = 1;
PIBlockingDequeue<int> dequeue(capacity);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
dequeue.offer(111);
ASSERT_EQ(dequeue.remainingCapacity(), 0);
@@ -220,7 +464,7 @@ TEST(BlockingDequeueUnitTest, remainingCapacity_is_zero_when_capacity_reach) {
TEST(BlockingDequeueUnitTest, size_is_eq_to_num_of_elements) {
size_t capacity = 1;
PIBlockingDequeue<int> dequeue(capacity);
PIBlockingDequeuePrepare<int> dequeue(capacity);
ASSERT_EQ(dequeue.size(), 0);
dequeue.offer(111);
ASSERT_EQ(dequeue.size(), 1);
@@ -228,7 +472,7 @@ TEST(BlockingDequeueUnitTest, size_is_eq_to_num_of_elements) {
TEST(BlockingDequeueUnitTest, size_is_eq_to_capacity_when_capacity_reach) {
size_t capacity = 1;
PIBlockingDequeue<int> dequeue(capacity);
PIBlockingDequeuePrepare<int> dequeue(capacity);
dequeue.offer(111);
dequeue.offer(111);
ASSERT_EQ(dequeue.size(), capacity);
@@ -236,29 +480,31 @@ TEST(BlockingDequeueUnitTest, size_is_eq_to_capacity_when_capacity_reach) {
TEST(BlockingDequeueUnitTest, drainTo_is_elements_moved) {
size_t capacity = 10;
PIDeque<int> refDeque;
std::deque<int> refDeque;
for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10);
PIBlockingDequeue<int> blockingDequeue(refDeque);
PIDeque<int> deque;
PIBlockingDequeuePrepare<int> blockingDequeue(refDeque);
PIBlockingDequeuePrepare<int>::QueueType deque;
blockingDequeue.drainTo(deque);
ASSERT_EQ(blockingDequeue.size(), 0);
ASSERT_TRUE(deque == refDeque);
// FIXME
// ASSERT_TRUE(deque == refDeque);
}
TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_size_when_all_moved) {
size_t capacity = 10;
PIDeque<int> refDeque;
std::deque<int> refDeque;
for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10);
PIBlockingDequeue<int> blockingDequeue(refDeque);
PIDeque<int> deque;
PIBlockingDequeuePrepare<int> blockingDequeue(refDeque);
PIBlockingDequeuePrepare<int>::QueueType deque;
ASSERT_EQ(blockingDequeue.drainTo(deque), refDeque.size());
}
TEST(BlockingDequeueUnitTest, drainTo_is_ret_eq_to_maxCount) {
size_t capacity = 10;
PIDeque<int> refDeque;
std::deque<int> refDeque;
for (size_t i = 0; i < capacity / 2; ++i) refDeque.push_back(i * 10);
PIBlockingDequeue<int> blockingDequeue(refDeque);
PIDeque<int> deque;
PIBlockingDequeuePrepare<int> blockingDequeue(refDeque);
PIBlockingDequeuePrepare<int>::QueueType deque;
ASSERT_EQ(blockingDequeue.drainTo(deque, refDeque.size() - 1), refDeque.size() - 1);
}
*/

View File

@@ -3,7 +3,7 @@
#include "pithread.h"
#include "testutil.h"
class ConditionVariable : public ::testing::Test, public TestUtil {
class ConditionVariableIntegrationTest : public ::testing::Test, public TestUtil {
public:
PIMutex m;
PIConditionVariable* variable;
@@ -19,30 +19,30 @@ protected:
}
};
TEST_F(ConditionVariable, wait_is_block) {
TEST_F(ConditionVariableIntegrationTest, wait_is_block) {
createThread();
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
}
TEST_F(ConditionVariable, wait_is_block_when_notifyOne_before_wait) {
TEST_F(ConditionVariableIntegrationTest, wait_is_block_when_notifyOne_before_wait) {
variable->notifyOne();
createThread();
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
}
TEST_F(ConditionVariable, wait_is_block_when_notifyAll_before_wait) {
TEST_F(ConditionVariableIntegrationTest, wait_is_block_when_notifyAll_before_wait) {
variable->notifyAll();
createThread();
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
}
TEST_F(ConditionVariable, wait_is_unblock_when_notifyOne_after_wait) {
TEST_F(ConditionVariableIntegrationTest, wait_is_unblock_when_notifyOne_after_wait) {
createThread();
variable->notifyOne();
ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
}
TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) {
TEST_F(ConditionVariableIntegrationTest, wait_is_unblock_when_notifyAll_after_wait) {
PIVector<PIThread*> threads;
for (int i = 0; i < THREAD_COUNT; ++i) {
@@ -61,7 +61,7 @@ TEST_F(ConditionVariable, wait_is_unblock_when_notifyAll_after_wait) {
piForeach(PIThread* thread, threads) delete thread;
}
TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) {
TEST_F(ConditionVariableIntegrationTest, wait_is_one_unblock_when_notifyOne) {
PIVector<PIThread*> threads;
for (int i = 0; i < THREAD_COUNT; ++i) {
@@ -77,7 +77,7 @@ TEST_F(ConditionVariable, wait_is_one_unblock_when_notifyOne) {
ASSERT_EQ(runningThreadCount, THREAD_COUNT - 1);
}
TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) {
TEST_F(ConditionVariableIntegrationTest, wait_is_protected_unblock_when_notifyOne) {
createThread([&](){
m.lock();
variable->wait(m);
@@ -89,7 +89,7 @@ TEST_F(ConditionVariable, wait_is_protected_unblock_when_notifyOne) {
ASSERT_FALSE(m.tryLock());
}
TEST_F(ConditionVariable, wait_condition_is_block) {
TEST_F(ConditionVariableIntegrationTest, wait_condition_is_block) {
createThread([&](){
m.lock();
variable->wait(m, [](){ return false; });
@@ -98,7 +98,7 @@ TEST_F(ConditionVariable, wait_condition_is_block) {
ASSERT_FALSE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
}
TEST_F(ConditionVariable, wait_condition_is_check_condition_before_block) {
TEST_F(ConditionVariableIntegrationTest, wait_condition_is_check_condition_before_block) {
bool isConditionChecked = false;
createThread([&](){
m.lock();
@@ -113,7 +113,7 @@ TEST_F(ConditionVariable, wait_condition_is_check_condition_before_block) {
m.unlock();
}
TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) {
TEST_F(ConditionVariableIntegrationTest, wait_condition_is_check_condition_when_notifyOne) {
bool isConditionChecked;
createThread([&](){
m.lock();
@@ -133,7 +133,7 @@ TEST_F(ConditionVariable, wait_condition_is_check_condition_when_notifyOne) {
m.unlock();
}
TEST_F(ConditionVariable, wait_condition_is_unblock_when_condition_and_notifyOne) {
TEST_F(ConditionVariableIntegrationTest, wait_condition_is_unblock_when_condition_and_notifyOne) {
bool condition = false;
createThread([&](){
m.lock();
@@ -147,7 +147,7 @@ TEST_F(ConditionVariable, wait_condition_is_unblock_when_condition_and_notifyOne
ASSERT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS));
}
TEST_F(ConditionVariable, DISABLED_waitFor_is_block_before_timeout) {
TEST_F(ConditionVariableIntegrationTest, DISABLED_waitFor_is_block_before_timeout) {
createThread([&](){
PITimeMeasurer measurer;
m.lock();
@@ -159,7 +159,7 @@ TEST_F(ConditionVariable, DISABLED_waitFor_is_block_before_timeout) {
EXPECT_TRUE(thread->waitForFinish(WAIT_THREAD_TIME_MS * 3));
}
TEST_F(ConditionVariable, waitFor_is_unblock_when_timeout) {
TEST_F(ConditionVariableIntegrationTest, waitFor_is_unblock_when_timeout) {
std::atomic_bool isUnblock(false);
createThread([&](){
m.lock();
@@ -172,7 +172,7 @@ TEST_F(ConditionVariable, waitFor_is_unblock_when_timeout) {
ASSERT_TRUE(isUnblock);
}
TEST_F(ConditionVariable, waitFor_is_false_when_timeout) {
TEST_F(ConditionVariableIntegrationTest, waitFor_is_false_when_timeout) {
bool waitRet = true;
createThread([&](){
m.lock();
@@ -183,7 +183,7 @@ TEST_F(ConditionVariable, waitFor_is_false_when_timeout) {
ASSERT_FALSE(waitRet);
}
TEST_F(ConditionVariable, waitFor_is_unblock_when_condition_and_notifyOne) {
TEST_F(ConditionVariableIntegrationTest, waitFor_is_unblock_when_condition_and_notifyOne) {
bool condition = false;
createThread([&](){
m.lock();

View File

@@ -1,8 +1,7 @@
#include "gtest/gtest.h"
#include "pithreadpoolexecutor.h"
#include "testutil.h"
#include "pimutex.h"
const int WAIT_THREAD_TIME_MS = 30;
#include "piexecutor.h"
TEST(ExcutorIntegrationTest, execute_is_runnable_invoke) {
PIMutex m;
@@ -14,11 +13,13 @@ TEST(ExcutorIntegrationTest, execute_is_runnable_invoke) {
m.unlock();
});
piMSleep(WAIT_THREAD_TIME_MS);
m.lock();
ASSERT_EQ(invokedRunnables, 1);
m.unlock();
}
TEST(ExcutorIntegrationTest, execute_is_not_execute_after_shutdown) {
bool isRunnableInvoke = false;
volatile bool isRunnableInvoke = false;
PIThreadPoolExecutor executorService(1);
executorService.shutdown();
executorService.execute([&]() {
@@ -29,7 +30,7 @@ TEST(ExcutorIntegrationTest, execute_is_not_execute_after_shutdown) {
}
TEST(ExcutorIntegrationTest, execute_is_execute_before_shutdown) {
bool isRunnableInvoke = false;
volatile bool isRunnableInvoke = false;
PIThreadPoolExecutor executorService(1);
executorService.execute([&]() {
piMSleep(WAIT_THREAD_TIME_MS);

View File

@@ -0,0 +1,131 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "testutil.h"
#include "piexecutor.h"
using ::testing::_;
using ::testing::SetArgReferee;
using ::testing::DoAll;
using ::testing::DeleteArg;
using ::testing::Return;
using ::testing::ByMove;
using ::testing::AtLeast;
using ::testing::ByRef;
using ::testing::Eq;
using ::testing::Ge;
using ::testing::Pointee;
using ::testing::IsNull;
using ::testing::NiceMock;
typedef std::function<void()> VoidFunc;
namespace std {
inline bool operator ==(const VoidFunc& s, const VoidFunc& v) {
// TODO VoidFunc operator ==
return true;
}
}
class MockThread {
public:
VoidFunc runnnable;
MockThread(VoidFunc runnnable) : runnnable(runnnable) { }
MOCK_METHOD0(start, bool());
MOCK_METHOD0(stop, void());
MOCK_METHOD1(waitForStart, bool(int timeout_msecs));
MOCK_METHOD1(waitForFinish, bool(int timeout_msecs));
};
class MockDeque : public PIBlockingDequeue<FunctionWrapper> {
public:
MOCK_METHOD1(offer, bool(const FunctionWrapper&));
MOCK_METHOD0(take, FunctionWrapper());
MOCK_METHOD1(poll, FunctionWrapper(int));
MOCK_METHOD0(capacity, size_t());
MOCK_METHOD0(remainingCapacity, size_t());
};
typedef PIThreadPoolExecutorTemplate<NiceMock<MockThread>, MockDeque> PIThreadPoolExecutorMoc_t;
class PIThreadPoolExecutorMoc : public PIThreadPoolExecutorMoc_t {
public:
explicit PIThreadPoolExecutorMoc(size_t corePoolSize) : PIThreadPoolExecutorMoc_t(corePoolSize) { }
template<typename Function>
explicit PIThreadPoolExecutorMoc(size_t corePoolSize, Function onBeforeStart) : PIThreadPoolExecutorMoc_t(corePoolSize, onBeforeStart) { }
PIVector<testing::NiceMock<MockThread>*>* getThreadPool() { return &threadPool; }
bool isShutdown() { return isShutdown_; }
MockDeque* getTaskQueue() { return &taskQueue; }
};
TEST(ExecutorUnitTest, is_corePool_created) {
PIThreadPoolExecutorMoc executor(THREAD_COUNT);
ASSERT_EQ(THREAD_COUNT, executor.getThreadPool()->size());
}
TEST(ExecutorUnitTest, is_corePool_started) {
PIThreadPoolExecutorMoc executor(THREAD_COUNT, [](MockThread* thread){
EXPECT_CALL(*thread, start())
.WillOnce(Return(true));
});
EXPECT_EQ(THREAD_COUNT, executor.getThreadPool()->size());
}
TEST(ExecutorUnitTest, submit_is_added_to_taskQueue) {
VoidFunc voidFunc = [](){};
PIThreadPoolExecutorMoc executor(THREAD_COUNT);
// TODO add check of offered
EXPECT_CALL(*executor.getTaskQueue(), offer)
.WillOnce(Return(true));
executor.submit(voidFunc);
}
TEST(ExecutorUnitTest, submit_is_return_valid_future) {
VoidFunc voidFunc = [](){};
PIThreadPoolExecutorMoc executor(THREAD_COUNT);
// TODO add check of offered
EXPECT_CALL(*executor.getTaskQueue(), offer)
.WillOnce(Return(true));
auto future = executor.submit(voidFunc);
EXPECT_TRUE(future.valid());
}
TEST(ExecutorUnitTest, execute_is_added_to_taskQueue) {
VoidFunc voidFunc = [](){};
PIThreadPoolExecutorMoc executor(THREAD_COUNT);
// TODO add check of offered
EXPECT_CALL(*executor.getTaskQueue(), offer)
.WillOnce(Return(true));
executor.execute(voidFunc);
}
TEST(ExecutorUnitTest, is_corePool_execute_queue_elements) {
bool is_executed = false;
PIThreadPoolExecutorMoc executor(1);
EXPECT_EQ(executor.getThreadPool()->size(), 1);
EXPECT_CALL(*executor.getTaskQueue(), poll(Ge(0)))
.WillOnce([&is_executed](int){
return FunctionWrapper([&is_executed](){ is_executed = true; });
});
executor.getThreadPool()->at(0)->runnnable();
ASSERT_TRUE(is_executed);
}
TEST(ExecutorUnitTest, shutdown_is_stop_threads) {
// Exclude stop calls when executor deleting
auto* executor = new PIThreadPoolExecutorMoc(THREAD_COUNT, [](MockThread* thread){
testing::Mock::AllowLeak(thread);
EXPECT_CALL(*thread, stop())
.WillOnce(Return());
});
testing::Mock::AllowLeak(executor);
testing::Mock::AllowLeak(executor->getTaskQueue());
EXPECT_CALL(*executor->getTaskQueue(), poll(Ge(0)))
.WillRepeatedly([](int){ return FunctionWrapper(); });
executor->shutdown();
executor->getThreadPool()->forEach([](MockThread* thread){ thread->runnnable(); });
}

View File

@@ -1,16 +1,14 @@
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "piconditionvar.h"
#include "pithread.h"
#include "testutil.h"
class ConditionLock : public ::testing::Test, public TestUtil {
class MutexIntegartionTest : public ::testing::Test, public TestUtil {
public:
PIMutex* m = new PIMutex();
};
TEST_F(ConditionLock, lock_is_protect) {
TEST_F(MutexIntegartionTest, lock_is_protect) {
m->lock();
bool* isProtect = new bool(true);
@@ -22,7 +20,7 @@ TEST_F(ConditionLock, lock_is_protect) {
ASSERT_TRUE(*isProtect);
}
TEST_F(ConditionLock, unlock_is_release) {
TEST_F(MutexIntegartionTest, unlock_is_release) {
m->lock();
bool* isReleased = new bool(false);
m->unlock();
@@ -35,7 +33,7 @@ TEST_F(ConditionLock, unlock_is_release) {
ASSERT_TRUE(*isReleased);
}
TEST_F(ConditionLock, tryLock_is_false_when_locked) {
TEST_F(MutexIntegartionTest, tryLock_is_false_when_locked) {
createThread([&](){
m->lock();
piMSleep(WAIT_THREAD_TIME_MS);
@@ -43,11 +41,11 @@ TEST_F(ConditionLock, tryLock_is_false_when_locked) {
ASSERT_FALSE(m->tryLock());
}
TEST_F(ConditionLock, tryLock_is_true_when_unlocked) {
TEST_F(MutexIntegartionTest, tryLock_is_true_when_unlocked) {
ASSERT_TRUE(m->tryLock());
}
TEST_F(ConditionLock, tryLock_is_recursive_lock_enable) {
TEST_F(MutexIntegartionTest, tryLock_is_recursive_lock_enable) {
m->lock();
ASSERT_TRUE(m->tryLock());
}

View File

@@ -1,60 +1,68 @@
#ifndef AWRCANFLASHER_TESTUTIL_H
#define AWRCANFLASHER_TESTUTIL_H
#include "pithread.h"
#include <atomic>
/**
* Minimum wait thread start, switch context or another interthread communication action time. Increase it if tests
* write "Start thread timeout reach!" message. You can reduce it if you want increase test performance.
*/
const int WAIT_THREAD_TIME_MS = 40;
const int THREAD_COUNT = 5;
class TestUtil: public PIObject {
PIOBJECT(TestUtil)
public:
double threadStartTime;
PIThread* thread = new PIThread();
std::atomic_bool isRunning;
std::function<void()> adapterFunctionDefault;
TestUtil() : isRunning(false) {}
bool createThread(const std::function<void()>& fun = nullptr, PIThread* thread_ = nullptr) {
std::function<void()> actualFun = fun == nullptr ? adapterFunctionDefault : fun;
if (thread_ == nullptr) thread_ = thread;
thread_->startOnce([=](void*){
isRunning = true;
actualFun();
});
return waitThread(thread_);
}
bool waitThread(PIThread* thread_, bool runningStatus = true) {
PITimeMeasurer measurer;
bool isTimeout = !thread_->waitForStart(WAIT_THREAD_TIME_MS);
while (!isRunning) {
isTimeout = WAIT_THREAD_TIME_MS <= measurer.elapsed_m();
if (isTimeout) break;
piUSleep(100);
}
threadStartTime = measurer.elapsed_m();
if (isTimeout) piCout << "Start thread timeout reach!";
if (threadStartTime > 1) {
piCout << "Start time" << threadStartTime << "ms";
} else if (threadStartTime > 0.001) {
piCout << "Start time" << threadStartTime * 1000 << "mcs";
} else {
piCout << "Start time" << threadStartTime * 1000 * 1000 << "ns";
}
return !isTimeout;
}
};
#endif //AWRCANFLASHER_TESTUTIL_H
#ifndef AWRCANFLASHER_TESTUTIL_H
#define AWRCANFLASHER_TESTUTIL_H
#include "pithread.h"
#include <atomic>
template<typename T>
void print_type_info() {
std::cout << typeid(T).name() << " is a "
<< (std::is_const<typename std::remove_reference<T>::type>::value ? "const " : "")
<< (std::is_lvalue_reference<T>::value ? "lvalue" : "rvalue")
<< " reference" << std::endl;
}
/**
* Minimum wait thread start, switch context or another interthread communication action time. Increase it if tests
* write "Start thread timeout reach!" message. You can reduce it if you want increase test performance.
*/
const int WAIT_THREAD_TIME_MS = 30;
const int THREAD_COUNT = 2;
class TestUtil: public PIObject {
PIOBJECT(TestUtil)
public:
double threadStartTime;
PIThread* thread = new PIThread();
std::atomic_bool isRunning;
std::function<void()> adapterFunctionDefault;
TestUtil() : isRunning(false) {}
bool createThread(const std::function<void()>& fun = nullptr, PIThread* thread_ = nullptr) {
std::function<void()> actualFun = fun == nullptr ? adapterFunctionDefault : fun;
if (thread_ == nullptr) thread_ = thread;
thread_->startOnce([=](void*){
isRunning = true;
actualFun();
});
return waitThread(thread_);
}
bool waitThread(PIThread* thread_, bool runningStatus = true) {
PITimeMeasurer measurer;
bool isTimeout = !thread_->waitForStart(WAIT_THREAD_TIME_MS);
while (!isRunning) {
isTimeout = WAIT_THREAD_TIME_MS <= measurer.elapsed_m();
if (isTimeout) break;
piUSleep(100);
}
threadStartTime = measurer.elapsed_m();
if (isTimeout) piCout << "Start thread timeout reach!";
if (threadStartTime > 1) {
piCout << "Start time" << threadStartTime << "ms";
} else if (threadStartTime > 0.001) {
piCout << "Start time" << threadStartTime * 1000 << "mcs";
} else {
piCout << "Start time" << threadStartTime * 1000 * 1000 << "ns";
}
return !isTimeout;
}
};
#endif //AWRCANFLASHER_TESTUTIL_H

View File

@@ -0,0 +1,28 @@
#include "dispatcherclient.h"
DispatcherClient::DispatcherClient(PIEthernet * eth_) {
eth = eth_;
eth->startThreadedRead();
CONNECTU(eth, threadedReadEvent, this, readed);
CONNECTU(eth, disconnected, this, disconnected);
piCoutObj << "client connected" << eth->sendAddress();
}
DispatcherClient::~DispatcherClient() {
}
void DispatcherClient::disconnected(bool withError) {
piCoutObj << "client disconnected" << eth->sendAddress();
disconnectEvent(this);
}
void DispatcherClient::readed(uchar *data, int size) {
PIByteArray ba(data, size);
piCoutObj << "readed" << ba.toHex();
eth->write(ba);
}

View File

@@ -0,0 +1,21 @@
#ifndef DISPATCHERCLIENT_H
#define DISPATCHERCLIENT_H
#include "piethernet.h"
class DispatcherClient: public PIObject {
PIOBJECT(DispatcherClient)
public:
DispatcherClient(PIEthernet * eth_);
~DispatcherClient();
EVENT_HANDLER2(void, readed, uchar * , data, int, size);
EVENT_HANDLER1(void, disconnected, bool, withError);
EVENT1(disconnectEvent, DispatcherClient *, client)
private:
PIEthernet * eth;
};
#endif // DISPATCHERCLIENT_H

View File

@@ -0,0 +1,32 @@
#include "dispatcherserver.h"
DispatcherServer::DispatcherServer(PIEthernet::Address addr) {
eth = new PIEthernet(PIEthernet::TCP_Server);
eth->setParameter(PIEthernet::ReuseAddress);
CONNECTU(eth, newConnection, this, newConnection);
eth->listen(addr, true);
piCoutObj << eth << "server started" << addr;
}
DispatcherServer::~DispatcherServer() {
eth->close();
piCoutObj << "server stoped";
delete eth;
}
void DispatcherServer::disconnectClient(DispatcherClient *client) {
piCoutObj << "remove client" << client;
clients.removeOne(client);
delete client;
}
void DispatcherServer::newConnection(PIEthernet *cl) {
DispatcherClient * client = new DispatcherClient(cl);
piCoutObj << "add client" << client;
CONNECTU(client, disconnectEvent, this, disconnectClient);
clients.push_back(client);
}

View File

@@ -0,0 +1,20 @@
#ifndef DISPATCHERSERVER_H
#define DISPATCHERSERVER_H
#include "dispatcherclient.h"
class DispatcherServer: public PIObject {
PIOBJECT(DispatcherServer)
public:
DispatcherServer(PIEthernet::Address addr);
~DispatcherServer();
EVENT_HANDLER1(void, newConnection, PIEthernet * , cl);
EVENT_HANDLER1(void, disconnectClient, DispatcherClient *, client);
private:
PIEthernet * eth;
PIVector<DispatcherClient*> clients;
};
#endif // DISPATCHERSERVER_H

View File

@@ -19,12 +19,12 @@
#include "pip.h"
#include "picrypt.h"
#include "dispatcherserver.h"
using namespace PICoutManipulators;
PIString ip = "0.0.0.0";
int port = 10101;
PIEthernet::Address addr = PIEthernet::Address("0.0.0.0", 10101);
void usage() {
piCout << Bold << "PIP Cloud Dispatcher";
@@ -49,10 +49,11 @@ int main (int argc, char * argv[]) {
return 0;
}
if (cli.hasArgument("ip"))
ip = cli.argumentValue("ip");
addr.setIP(cli.argumentValue("ip"));
if (cli.hasArgument("port"))
port = cli.argumentValue("port").toInt();
addr.setPort(cli.argumentValue("port").toInt());
DispatcherServer server(addr);
WAIT_FOR_EXIT
return 0;
}

View File

@@ -87,7 +87,8 @@ void makeClassInfo(PIFile & f, const PICodeParser::Entity * e) {
f << "\tci->name = \"" << e->name << "\";\n";
f << "\tci->has_name = " << (e->has_name ? "true" : "false") << ";\n";
if (!e->meta.isEmpty()) {
for (PICodeParser::MetaMap::const_iterator i = e->meta.begin(); i != e->meta.end(); ++i)
auto i = e->meta.makeIterator();
while (i.next())
f << "\tci->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
}
f << "\t(*classesInfo)[ci->name] = ci;\n";
@@ -176,14 +177,16 @@ void makeEnumInfo(PIFile & f, const PICodeParser::Enum * e) {
f << "\t(*enumsInfo)[\"" << e->name << "\"] = ei;\n";
f << "\tei->name = \"" << e->name << "\";\n";
if (!e->meta.isEmpty()) {
for (PICodeParser::MetaMap::const_iterator i = e->meta.begin(); i != e->meta.end(); ++i)
auto i = e->meta.makeIterator();
while (i.next())
f << "\tei->meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
}
}
piForeachC (PICodeParser::EnumeratorInfo & m, e->members) {
f << "\tei->members << PICodeInfo::EnumeratorInfo(\"" << m.name << "\", " << m.value << ");\n";
if (!m.meta.isEmpty()) {
for (PICodeParser::MetaMap::const_iterator i = m.meta.begin(); i != m.meta.end(); ++i)
auto i = m.meta.makeIterator();
while (i.next())
f << "\tei->members.back().meta[\"" << i.key() << "\"] = PIString::fromUTF8(\"" << i.value() << "\");\n";
}
}

View File

@@ -583,8 +583,9 @@ int main(int argc, char * argv[]) {
qt_filters["platforms"] = platforms;
qt_filters["styles" ] = styles ;
for (PIMap<PIString, PIStringList>::iterator it = qt_filters.begin(); it != qt_filters.end(); ++it)
it.value().forEachInplace([](PIString i)->PIString{
auto it = qt_filters.makeIterator();
while (it.next())
it.valueRef().forEachInplace([](PIString i)->PIString{
if (!i.startsWith("*")) i.prepend("*");
if (!i.endsWith("*")) i.append("*");
return i;

View File

@@ -23,6 +23,8 @@ int main (int argc, char * argv[]) {
return 0;
}
#else
# define PIP_CONSOLE_STATIC_DEFINE
# include "pip_console_export.h"
# include "piscreentypes.h"
# include "pisharedmemory.h"
# include "pifile.h"