Compare commits

389 Commits

Author SHA1 Message Date
8e96750046 version 4.7.0
add PIEthernet socket options setReadBufferSize() and setWriteBufferSize()
add PIByteArray::dataAs
2025-02-06 11:13:43 +03:00
d01baffb0b PITimeMeasurer remove some API, add elapsedAndReset()
got rid off some warnings
2025-01-17 11:49:24 +03:00
82cda42e75 change last logic to PIThreadNotifier 2025-01-15 18:38:50 +03:00
5755d172cd fallback to min_sleep 2025-01-15 18:25:32 +03:00
0dd47f50a0 version 4.6.0
PIThreadNotifier::waitFor() new method
PIThread::waitForFinish() now use condvar to exit as soon as possible
2025-01-15 17:57:16 +03:00
60d2a83df5 android (maybe some other *nix) fix 2025-01-10 20:46:33 +03:00
7757ac10ec add PIP_BUILD_<MODULE> options for PIP build to force disabling modules 2025-01-09 17:36:40 +03:00
f334a6603f adopt for new MinGW 2025-01-06 12:55:44 +03:00
15548de79c version 4.5.0
PIThread::stopAndWait now returns bool
PIKbdListener on Linux now use piwaitevent_p and can immediately stop
new base method piZeroMemory, also migrate all "memset 0" to piZeroMemory
2024-12-29 11:48:24 +03:00
49713ddc57 PIThread now setup itself in thread func 2024-12-29 10:50:38 +03:00
0973379f53 now works 2024-12-26 16:19:33 +03:00
a3004491d6 no warning on terminate kbd 2024-12-26 16:18:13 +03:00
199a272eb8 now rude 2024-12-26 16:16:01 +03:00
855d1ca1b5 try to fix hang on exit by keyboard 2024-12-26 16:12:02 +03:00
64025e0399 PIThread now wait on _endThread() when starting is really done 2024-12-26 16:01:56 +03:00
6e5556969d fix for last commit 2024-12-25 19:37:55 +03:00
b50eeaef46 fix for last commit 2024-12-25 19:34:49 +03:00
ffc471359a fix thread name for linux 2024-12-25 19:30:15 +03:00
79007e7b4e PIString::arg() now ignore non-suitable %.
PIVector and PIDeque now use std::stable_sort
2024-12-07 12:57:48 +03:00
9e08b6ffc5 turn fuck off tests by default anyway 2024-12-03 15:41:34 +03:00
9b8a1583c2 add "--no-strip" flag to deploy_tool 2024-12-03 11:19:14 +03:00
cae264a77b forgot to implement PIHTTPClient headers 2024-11-28 13:13:08 +03:00
4f934fef35 PIHTTPClient fixes 2024-11-28 12:37:05 +03:00
3a159b0553 PIByteArray operators & | ^
PIDigest add BLAKE2 algorithms and HMAC
2024-11-27 18:27:51 +03:00
0c973f0216 add PIDigest with SHA and MD series 2024-11-27 14:40:39 +03:00
65d3168eb5 PICout::withExternalBufferAnd decomposed to PICout::withExternalBufferAndID and PICout::withExternalBufferAnd
PIString::toPercentageEncoding/fromPercentageEncoding
piStringify()
PIHTTPClient support arguments
some doc
2024-11-26 18:26:02 +03:00
12114b3e77 old curl fix 2024-11-25 16:02:40 +03:00
6f6b717354 pip_test 2024-11-25 15:53:12 +03:00
58b3fa64bc http server fix 2024-11-25 15:00:42 +03:00
1acaf24df9 PIHTTPServer basic auth works 2024-11-24 23:23:08 +03:00
c2c9822169 fix FindPIP.cmake 2024-11-23 17:55:59 +03:00
dff4f2b3a0 add http_client library, using libcurl
take out common http entities to http_common dir
2024-11-23 17:54:22 +03:00
bf9ad65ff0 take out "asize" from vector/dequeue to picontainers.h->calcNewSize()
minAlloc and maxPoTAlloc now can be override from CMake by PIP_CONTAINERS_MIN_ALLOC and PIP_CONTAINERS_MAX_POT_ALLOC variables
2024-11-21 20:15:18 +03:00
53ec75bf0c remove junk 2024-11-21 16:31:40 +03:00
f5270d75eb multi-utf16 fix 2024-11-21 16:28:19 +03:00
4aa596b179 last commit error 2024-11-21 00:18:57 +03:00
002f21fc9e version 4.4.1 2024-11-21 00:10:35 +03:00
9ab46e4afc version 4.4.1
PIVector and PIDeque now growth to 64 MiB with PoT, then increments size by 64 MiB
in case of large containers it significantly save memory
2024-11-21 00:10:14 +03:00
caa7880cc4 get rid of piForeach
apply some code analyzer recommendations
ICU flag now check if libicu exists
prepare for more accurate growth of containers (limited PoT, then constantly increase size)
2024-11-20 20:01:47 +03:00
24112498ce new method PILog::readAllLogs 2024-11-18 22:47:02 +03:00
c9a5ddd89f PIProtectedVariable - user now can`t mistake
PIHTTPServer improvements
2024-11-18 11:11:19 +03:00
3483edbd76 Merge pull request 'refactoring PICrypt, add PIStreamPackerConfig, delete piclientserver_config' (#184) from pisteampackerconfig into master
Reviewed-on: #184
2024-11-16 15:44:15 +03:00
fe82c12d5b fix build 2024-11-16 14:53:04 +03:00
d90c3f0991 Merge branch 'master' into pisteampackerconfig
# Conflicts:
#	libs/client_server/piclientserver_server.cpp
#	libs/crypt/picrypt.cpp
#	libs/io_utils/pistreampacker.cpp
#	main.cpp
2024-11-16 14:34:34 +03:00
f6b9131f4a test excluded for android 2024-11-15 17:14:19 +03:00
c67f7a2b64 log fix 2024-11-15 16:23:48 +03:00
047d38ea59 http includes 2024-11-15 15:47:56 +03:00
3d07795515 add_custom_command(... pip_lang) on ninja brings to resursive cmake and ninja call ( 2024-11-15 15:43:03 +03:00
ee137b2820 http server options, remove old 2024-11-15 14:18:49 +03:00
cdde340efe add microhttpd server 2024-11-14 18:15:27 +03:00
ee34e8a72e doc 2024-11-13 16:32:21 +03:00
0840d807a0 add PIReadWriteLock, PIReadLocker and PIWriteLocker 2024-11-13 13:56:16 +03:00
4655d72554 new class PISemaphore
doc for PIProtectedVariable
2024-11-12 18:50:22 +03:00
5b066cbc27 add PIProtectedVariable 2024-11-10 21:28:59 +03:00
2247473959 PICodeParser namespace fix 2024-11-07 15:43:13 +03:00
57f8c1313e first release of translation facility
* runtime - loading and translating
 * design-time - works with *.ts file (pip_tr utility)
 * compile-time - CMake macro for compile *.ts
2024-11-05 13:49:00 +03:00
73ed51e3d4 translations: multi-line and special symbols support 2024-11-03 18:12:32 +03:00
1106cde3e4 return tr for PIString 2024-11-03 14:41:31 +03:00
b43158d3a8 add PIString::lineNumber() method
add ""_tr literal to translate string by PITranslator
add pip_tr util, now useless, only can generate *.ts
add qt_support internal lib, now only works with *.ts file
pip_vtt migrate to qt_support
2024-11-03 14:39:42 +03:00
9a928f6feb add PITranslator
begin localization "ru"
2024-11-02 18:43:30 +03:00
df75efe881 version 4.3.2
fix PIKbdListener wheel on Windows
2024-11-02 14:15:09 +03:00
9f1d23ad8e version 4.3.1
PICodeParser now works with multi-line macros
2024-10-23 19:11:46 +03:00
7cd2f7a310 PIBinaryStream supports PISet 2024-10-21 13:47:28 +03:00
315966504e fix picrypt and remove crypt_frag from PIStreamPacker 2024-10-20 18:03:25 +03:00
7209eec012 author 2024-10-19 17:08:15 +03:00
992f59904a more documentation 2024-10-19 17:07:45 +03:00
9dbd7210cb PILog documentation 2024-10-19 16:58:12 +03:00
ac8efc9f88 need fix PIPackedTCP 2024-10-18 19:00:39 +03:00
92a0a9356c refactoring PICrypt, add PIStreamPackerConfig, delete piclientserver_config 2024-10-18 18:59:20 +03:00
28f3471036 version 4.3.0 2024-10-16 22:29:57 +03:00
d3d7235338 enable complex type for PIMathVectorT and PIMathMatrixT
TODO: add precision to invert and test vector
2024-10-16 22:10:28 +03:00
92a87a0c64 picloud add "-w" option for watchdog 2024-10-15 15:04:39 +03:00
cd7e053fc5 version 4.2.0
move toStdFunction() to pibase.h
refactor PIParseHelper, now it much more abstract and useful
fix PIIODevice::createFromFullPath() when whitespaces at start or end are presence
PIStreamPacker add events for start and end packet receive
PIClientServer::ClientBase add virtual methods for start and end packet receive. also one can enable diagnostics with enableDiagnostics() method
PICout now call flush() on each end of output
add PIString::entries(const PIString & str)
2024-10-15 12:02:18 +03:00
9eecbbab6e new method PIClientServer::Server::closeAll()
PISignals::releaseSignals()
2024-09-24 18:57:50 +03:00
3641e636d2 new PIClientServer::ClientBase::stopAndWait() method for blocking stop read.
PIClientServer::ClientBase::close() now non-blocking
2024-09-21 19:56:39 +03:00
4acab04895 PILog ready to use 2024-09-19 17:26:58 +03:00
aa963a4bda PIEthernet on error close disconnect 2024-09-17 16:50:22 +03:00
bdd18b614f PIEthernet more accuracy construct
PIThread windows fix
2024-09-17 16:11:18 +03:00
e186e0adff shorter thread names 2024-09-17 15:58:06 +03:00
f105f616f6 PIThread more accurate end, PIEthernet tcpserver client no reinit 2024-09-17 13:22:20 +03:00
andrey.bychkov
b99c51181d fix test 2024-09-17 12:31:03 +03:00
andrey.bychkov
bc6b584480 fix waitLoop 2024-09-17 11:28:34 +03:00
eb97de1413 close 2024-09-17 11:21:23 +03:00
97f1c25ff8 close 2024-09-17 11:15:50 +03:00
97aad47a21 some fixes 2024-09-16 23:32:01 +03:00
43bd1d8550 Merge remote-tracking branch 'remotes/origin/tests_client_server' into test 2024-09-16 19:58:26 +03:00
andrey.bychkov
3255199b3f Unit tests for PIClientServer 2024-09-16 19:54:44 +03:00
224412e20a PIDir::temporary fix 2024-09-16 16:24:11 +03:00
000ce2a54d PICout improvement:
* renamed private members for more clear code
 * registerExternalBufferID() method to obtain unique ID for withExternalBuffer()
 * PICoutManipulators::PICoutStdStream enum for select stream (stdout or stderr)
 * Constructors now accept optional stream
 * piCerr and piCerrObj macros

PIDir::temporary() moved to "mkdtemp"

PILog:
 * now 4 levels
 * you can set max level
 * Error writes to piCerr
2024-09-16 16:06:07 +03:00
andrey.bychkov
f992bf4cbb build fix 2024-09-16 10:43:22 +03:00
andrey.bychkov
96625bd93d minor clean 2024-09-16 10:11:31 +03:00
9d4357c066 PIVector2D =() fix 2024-09-15 16:50:15 +03:00
7a945f47b1 PILog works 2024-09-13 23:05:24 +03:00
9a352bfc83 add PISystemTime::toFrequency(), add PILog 2024-09-13 18:00:48 +03:00
aa2f117075 finalize module 2024-09-13 13:37:09 +03:00
bf5bb45771 decompose, add new main group "Application"
PICLI code brush
2024-09-13 13:31:31 +03:00
cdc966bd8c Merge pull request 'client_server' (#181) from client_server into master
Reviewed-on: #181
2024-09-13 12:12:10 +03:00
17b902ebcc add PIClientServer::Config, common configuration type for both sides, stream packer and encryption settings 2024-09-13 11:08:32 +03:00
996b7ea403 important:
* PIThread::~PIThread() now unregister itself from introspection, if terminates than show warning
 * PISystemMonitor now correctly stops
 * PIPeer now can correctly stopAndWait
 * PIPeer::destroy(), protected method for close all eths and threads
 * new PIINTROSPECTION_STOP macro
 * Introspection now can be correctly stopped by macro, more safety

ClientServer:
 * ClientBase::close() stop and disconnect channel
 * Server clients clean-up now event-based
 * No warnings on client destructor
2024-09-12 17:07:48 +03:00
da4b09be9e PIEthernet fix tcp-server close (properly delete all clients)
PIEthernet::stopThreadedListen() method
decompose client to 2 implementations - server-side and client-side
2024-09-11 21:41:55 +03:00
b24b5a1346 add encryption 2024-09-11 15:44:02 +03:00
0d94699206 first try, works 2024-09-11 10:18:45 +03:00
16a818c95e picloud hang fix try :`-( 2024-09-06 08:05:26 +03:00
a0454b809d change to private section 2024-08-28 17:21:11 +03:00
af8c096c7a PIStateMachine "addOnFinish" renamed to "setOnFinish" 2024-08-28 13:48:33 +03:00
14cf81aed0 remove void piLetobe(T * v) 2024-08-28 13:17:38 +03:00
c43b914fb3 PIMemoryBlock fix 2024-08-28 12:19:57 +03:00
f002f6cedd PIMemoryBlock fix 2024-08-28 12:19:37 +03:00
ce846eca51 fix deprecated message 2024-08-28 11:58:58 +03:00
e6c8714857 version 4.1.0
maybe fix hang on PIEthernet::interrupt()
replace piLetobe with piChangeEndian:
 * piChangeEndianBinary
 * piChangeBinary
 * piChangedBinary
PIDiagnostics::start now accept PISystemTime instead of number
add PITimer::start(PISystemTime, std::function<void()>) overload
2024-08-28 11:56:36 +03:00
33fc334077 PIStateMachine::postEvent() now thread-safe and can be recursive 2024-08-05 23:25:23 +03:00
6efc962923 in my opinion, PIStateMachine is ready to real work 2024-08-04 20:26:39 +03:00
7d02f710ea add PIPackedTCP 2024-08-02 14:43:42 +03:00
c8876807ed fix unidemponetial behaviour with PIP version 2024-07-30 17:21:30 +03:00
f43f834460 !! 2024-07-30 14:48:00 +03:00
ccf6b810b5 -librt is still need... 2024-07-30 14:41:54 +03:00
a438c4249d version fix 2024-07-30 14:26:07 +03:00
1c7fc39b6c version 4.0.0_alpha
in almost all methods removed timeouts in milliseconds, replaced to PISystemTime
PITimer rewrite, remove internal impl, now only thread implementation, API similar to PIThread
PITimer API no longer pass void*
PIPeer, PIConnection improved stability on reinit and exit
PISystemTime new methods
pisd now exit without hanging
2024-07-30 14:18:02 +03:00
f07c9cbce8 add timeout transition 2024-07-28 20:16:52 +03:00
abdba6d68b state machine, parallel seems to work, final state and info about active atomic states 2024-07-17 21:11:01 +03:00
3db26a762c first state machine code, exclusive already works
need to make final, parallel, timeouts
2024-07-17 14:16:25 +03:00
b35561f74e doc fix 2024-07-17 14:14:38 +03:00
f041d1435e PIIODevice::waitThreadedReadFinished now periodically (100 ms) call interrupt() 2024-07-10 18:36:29 +03:00
b781bd5148 PIBroadcast fix 2024-07-10 16:56:40 +03:00
a16e0b7659 substitution fix 2024-07-09 21:47:18 +03:00
0bafd3fa98 PIValueTree improvements: methods with path (recursive), forEachRecursive()
PIValueTreeConvertions::fromTextFile now can include other files and handle ${} substitutions
2024-07-09 21:44:30 +03:00
903b320629 version 3.21.0
add PISystemTime overload for thread/timer/io classes
2024-07-09 16:32:27 +03:00
9cd05996e7 version 3.20.0 2024-06-07 00:22:44 +03:00
15dc76c4a7 1 2024-06-06 22:06:40 +03:00
d46b5e008a try to fix cloud again 2024-06-01 22:27:39 +03:00
af4b718053 PIValueTree::contains fix for null entry 2024-05-22 15:15:32 +03:00
7eae1e127c PIBroadcast polishing 2024-05-14 21:01:53 +03:00
f97fed7daa string append more protection 2024-05-13 22:29:22 +03:00
d764171c82 Обновить libs/main/containers/pipair.h 2024-05-13 14:35:49 +03:00
d4a024ea75 remove harmful createPIPair() 2024-05-06 19:22:22 +03:00
491d89f117 version 3.19.0
PIMathVectorT subvector methods
PISystemTime::isNull()
PISystemTime::Frequency::isNull()
PISystemTime::toString()
PISystemTime::fromString()
PIVariant can handle strings with PISystemTime
PIDateTime::toSystemTime() now returns null time from invalid strings
2024-05-05 00:17:52 +03:00
a86e8f7b58 PIIOTextStream(PIString * string) now with mandatory Mode 2024-05-02 21:35:29 +03:00
d97798d063 version 3.18.1
fix pip_cmg - ignore static members
2024-04-30 15:23:26 +03:00
247759b364 version 3.18.0
PIMathMatrixT:: toType(), submatrix() and setSubmatrix()
2024-04-26 15:37:06 +03:00
a745f803b3 version 3.17.1
add PINonTriviallyCopyable struct
add PISerial check for error on Windows on every read()
2024-04-10 20:49:27 +03:00
1b67000887 PIPacketExtractor Timeout mode fix 2024-04-08 21:23:11 +03:00
04d3e31dbc PISet fix 2024-04-05 21:02:37 +03:00
9f29155d07 PISet fixes 2024-04-05 20:59:59 +03:00
021411defa PIConfig adopt for PIIOString changes 2024-04-05 20:41:07 +03:00
ee4d78d2e1 add PISet::const_iterator, now can iterate ranged-for PISet by T, not by PIPair<T, bool> 2024-04-05 17:13:18 +03:00
9283c88b4e version 3.17.0
finally properly works PIIOString inside PIIOStream
2024-04-05 15:34:38 +03:00
8d585439bb add PIChunkStream::getData(int id)
fix some COM on Windows
fix PIPacketExtractor
2024-04-04 20:50:44 +03:00
ebf2b08bb1 PIPacketExtractor fix 2024-04-04 12:34:00 +03:00
eb21c85170 version 3.16.1 2024-03-31 20:38:13 +03:00
fb68a9f9fe another segv on cloud 2024-03-31 20:31:35 +03:00
c7c3852747 cloud! finally fixed bug! 2024-03-25 22:40:29 +03:00
c18d0c918e 4 2024-03-25 21:45:59 +03:00
9c4fd41eef 3 2024-03-25 21:37:05 +03:00
9173dc936d 2 2024-03-25 21:34:30 +03:00
77c8681b43 1 2024-03-25 21:31:41 +03:00
2db9440a38 fix cloud ... :-/ 2024-03-25 21:24:29 +03:00
0d585cfebf cloud fix ... (( 2024-03-25 21:17:05 +03:00
02a9bfb76f another try fix 2024-03-22 22:29:14 +03:00
ad7385c21f more couts 2024-03-22 21:40:04 +03:00
dd6d91ac1d cloud fixes ... 2024-03-18 10:45:57 +03:00
576d9c79be Merge branch 'master' of https://git.shstk.ru/SHS/pip 2024-03-15 19:49:46 +03:00
3fa5d9d9df cloud inspecting ... 2024-03-15 19:49:37 +03:00
b14d30108a Optimization removeAll and removeWhere in PIVector and PIDeque (#180)
Reviewed-on: #180
Co-authored-by: Andrey Bychkov <andrey@signalmodelling.ru>
Co-committed-by: Andrey Bychkov <andrey@signalmodelling.ru>
2024-03-13 10:43:02 +03:00
2b738f6f43 more safety cloud_dispatcher 2024-03-10 21:22:05 +03:00
263fa18726 add warnings 2024-03-05 19:38:53 +03:00
f47bc411bc version 3.16.0
new PISystemTime::Frequency type
2024-03-05 17:55:25 +03:00
154fb7d9fd pip_vtt support special characters 2024-02-29 13:03:38 +03:00
9f09af9f27 doc to shstk.ru 2024-02-28 10:49:29 +03:00
960e4a7cce migrate to shstk.ru 2024-02-28 10:27:34 +03:00
50bff12364 map and cloud fix, add cloud debug 2024-02-22 17:10:38 +03:00
7297b9aee0 PICodeParser::parseFileContent 2024-01-25 23:58:50 +03:00
3652705784 usb 2024-01-17 18:39:53 +03:00
851f101470 usb 2024-01-17 18:38:40 +03:00
6b87536d8d usb fix 2024-01-17 18:32:06 +03:00
d299a1f386 support for multi ctor CONNECTL 2023-12-12 22:05:06 +03:00
c8350d2f0a doc 2023-12-09 07:25:48 +03:00
7efdacc979 main fix 2023-12-09 07:19:28 +03:00
c77afcc374 PICodeInfo compatible with old interface, safety access to PICODEINFO 2023-12-08 19:01:22 +03:00
b8fc44714c version 3.15.0 - improved pip_cmg and PICodeInfo storage
Important! changed API to access PICodeInfo storage
2023-12-08 16:14:18 +03:00
49a5ed6aa3 deploy_tool remove empty 2023-11-20 23:33:34 +03:00
76c76b48c5 OpenCL lib 2023-11-20 21:19:14 +03:00
03bd23a3b9 enable PIString2StdWString 2023-11-09 00:31:27 +03:00
61e6edb4c8 add PIOpenCL::Kernel::waitForFinish() 2023-09-25 14:28:15 +03:00
aa78e930be add toolTip attribute to PIValueTree 2023-09-13 10:33:12 +03:00
bb668dab29 ignore cross-compile dependencies 2023-09-07 13:11:26 +03:00
d1662d3535 PITextStream add long 2023-09-06 20:26:38 +03:00
12b136a2f4 version 3.14.1 2023-09-05 20:15:12 +03:00
aa69815a31 pip_cmg less code 2023-09-05 19:42:45 +03:00
3afa0ce0ab PIChunkStream::extract changed to PIBinaryStream 2023-08-30 17:08:11 +03:00
64a474c343 more safety 2023-08-30 12:29:06 +03:00
0907a3eb13 version 3.14.0
PIBinaryStream::wasReadError() method, remove incomplete read asserts
2023-08-30 12:18:04 +03:00
c86ec0ae82 normalizeAngleDeg methods 2023-08-14 12:37:32 +03:00
ac76e07d9d version 3.13.2 2023-07-14 22:14:02 +03:00
56aed70425 version 3.13.1 2023-07-14 10:51:01 +03:00
63321a4ce3 doc fix 2023-07-13 13:08:27 +03:00
66fb93ba88 change PIMap::at and add const to PIMap and PIBinaryLog 2023-07-13 12:32:45 +03:00
299a009d61 fix tests 2023-07-12 19:37:59 +03:00
4d395f4487 pivaluetreeconversions add file methods 2023-07-07 11:51:06 +03:00
2f82aaf97b missed include 2023-07-06 22:35:25 +03:00
13ececf370 linux fix 2023-07-06 21:57:41 +03:00
b19d50ba62 linux 2023-07-06 21:48:42 +03:00
b763f0e5cd version 3.13.0
Breaking changes in PIChar and PIString
2023-07-06 20:09:45 +03:00
27f6f5158d Merge pull request 'добавил const для части контейнеров и explicit для конструкторов' (#176) from const_explicit into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/176
2023-07-06 20:01:25 +03:00
61f1a34c14 PIString/PIChar explicit, support char16_t 2023-07-06 19:59:26 +03:00
8ad2503c5a pichar and pistring explicit test 2023-07-06 18:37:42 +03:00
1a96dc0cb9 PITimeMeasurer doc ru 2023-07-05 20:53:36 +03:00
de810b7bd6 auto-generated doc for PIValueTree 2023-07-04 22:50:25 +03:00
35aadb0e78 doc and brush 2023-07-04 13:08:37 +03:00
3a6b3a4064 добавил const для части контейнеров и explicit для конструкторов 2023-07-03 19:10:36 +03:00
9e78546b7e small fix 2023-07-02 14:12:48 +03:00
ccae1a7311 more literals, use some in PIP, small refactor PIThread::start (clang-format mistakes) 2023-07-02 14:02:10 +03:00
54d0ba1876 literals doc 2023-06-29 18:37:09 +03:00
d1193e7aa1 version 3.12.1
add piliterals.h
2023-06-29 18:20:24 +03:00
6c6437e980 typo fix 2023-06-21 17:20:07 +03:00
17e75c2951 expand ignored extensions for deploy_tool 2023-06-19 21:46:48 +03:00
c4766f8f5b piMin/piMax can accept any arguments count 2023-06-19 21:35:49 +03:00
1a214cff4e version 3.12.0
split pibase.h into 2 files
add PIScopeExitCall
2023-06-18 22:02:20 +03:00
dd56b1c142 deploy_tool - no objdump errors, Qml modules support, Windows custom Qt plugins and qml root directories 2023-06-14 23:30:48 +03:00
0ae63fa9ad Merge branch 'master' of https://git.shs.tools/SHS/pip 2023-05-24 22:13:35 +03:00
5e4c5b0d47 pichunkstream support full uint 2023-05-24 22:13:30 +03:00
58dcf7ba69 small fixes 2023-05-12 11:47:21 +03:00
1de4304e30 PIBinaryLog createIndexOnFly, loadIndex, saveIndex features
PIFile readAll and writeAll static methods
2023-05-11 21:44:31 +03:00
96e8ef2b23 .clang-format 2023-05-04 14:14:08 +03:00
dea29429bf PIBinaryLog support for uint ID 2023-05-03 22:12:56 +03:00
f5392f8b63 PIValueTree::readChildValue method
some child-oriented methods
allow to create JSON from single PIValueTree
2023-04-28 14:40:55 +03:00
3ab57eea88 PIProcess exit code for Windows 2023-04-25 17:15:00 +03:00
f503e85507 PIValueTree::childValue method 2023-04-24 19:03:36 +03:00
0f19719a98 fix CMake policy check 2023-04-23 23:15:55 +03:00
ee7251c17c PIDir::name() 2023-04-22 23:22:23 +03:00
2780dacb48 new piDeleteSafety() method 2023-04-13 20:40:14 +03:00
dea469d85e PIValueTree save issue 2023-04-10 13:16:59 +03:00
254649aa10 PIIOTextStream for strings fix 2023-04-07 19:43:56 +03:00
7badc531ce support PICodeParser "enum class" 2023-04-06 21:11:01 +03:00
6d3b7c8543 version 3.10.0
PIDir::CurrentDirOverrider and PIDir::absolute
2023-04-05 11:56:58 +03:00
4af5886649 some doc, deploy tool fix 2023-04-04 13:05:09 +03:00
38bcb6c482 picrypt.h doc 2023-03-28 17:43:30 +03:00
eb91ee1b35 deploy_tool now add wayland platform in addition to xcb 2023-03-26 18:16:14 +03:00
Бычков Андрей
2d1c86bc83 PIByteArray optimization - takeRange 2023-03-24 17:08:42 +03:00
d66f7efb3c fix include 2023-03-21 14:48:08 +03:00
20bdf3af61 version 2023-03-21 13:53:23 +03:00
49f5de26eb PIValueTree::applyValues now can be recursive 2023-03-21 14:55:55 +03:00
0cd1206f94 version 3.9.0, add PIEthernet::NoDelay parameter 2023-03-21 10:14:05 +03:00
df82102798 cmake fixes 2023-03-16 09:41:53 +03:00
650dadc347 new gtest 2023-03-16 09:34:34 +03:00
504fc5c896 small fixes 2023-03-14 17:41:12 +03:00
162f8e25fd pow10 error 2023-03-13 14:18:42 +03:00
e0900b6bd5 piDeleteAll fix 2023-02-11 15:56:14 +03:00
f3540d54b4 fix pichar 2023-02-10 12:39:32 +03:00
d743cc66d8 PIValueTree::applyValues 2023-02-07 23:24:43 +03:00
df4dcd7f32 PIGeoPosition as PIVariant support 2023-01-29 20:27:43 +03:00
3391d88460 version 3.8.2
PIObject::Connection::disconnect() now const
PIObject::deleted now public
2023-01-26 23:54:17 +03:00
5d75f1d298 PIValueTree::standardAttributes 2023-01-26 12:31:54 +03:00
73d482ebe2 PICloudClient interrupt fix 2023-01-10 12:10:35 +03:00
9ed66db515 version 3.8.0 2023-01-09 15:43:05 +03:00
c64a1beefa PISerial::readDevice 2023-01-09 15:39:46 +03:00
677ae06df8 PIIODevice::readForTime fix 2023-01-09 15:35:20 +03:00
5cc5369d2a missed include 2023-01-09 15:27:53 +03:00
5c16953d95 PIVariant, PIGPIO 2023-01-09 15:22:51 +03:00
f355cfc05e some PIFile functionality
PIBinaryLog::close fix
2022-12-26 14:09:05 +03:00
81cbf905ba PIValueTree add attributes 2022-12-20 16:10:38 +03:00
2732595efe CMakeLists.txt 2022-12-20 10:02:51 +03:00
2ac215c19e separate PIEthernet::Address to PINetworkAddress, typedef PIEthernet::Address to PINetworkAddress and mark as deprecated
PIValueTree new attributes for File and Dir
2022-12-19 14:29:18 +03:00
6c3f305562 improve pip_vtt - no-obsolete option, <location> support 2022-12-19 11:53:46 +03:00
fd82f5316c add pip_vtt util 2022-12-18 20:40:49 +03:00
a98176f513 PISerial Windows read fix 2022-12-18 14:23:19 +03:00
886eb06880 new attribute 2022-12-16 23:06:21 +03:00
581c7c937a .editorconfig 2022-12-16 16:45:07 +03:00
5836c64e5e .editorconfig 2022-12-16 16:41:20 +03:00
badcfac616 some PIValueTree changes, fix PIVariantTypes::Enum::fromString 2022-12-15 13:05:15 +03:00
c2b8a8d6da code format 2022-12-14 14:13:52 +03:00
430a41fefc before formatting 2022-12-14 13:56:19 +03:00
c74ba871cd pivariant, enum, tiny format 2022-12-13 21:44:06 +03:00
9d9357b0ca add .clang_format file 2022-12-12 12:40:24 +03:00
c4cb81a104 PIJSON::toJSON with optionally unicode masking
PIVariantTypes::Color::toName()
2022-12-08 13:21:11 +03:00
b609ce8027 version 3.7.0 2022-12-07 10:56:01 +03:00
0bd45ec49b friend with UNICODE macro on windows 2022-12-07 09:33:46 +03:00
3625627072 PIVariantTypes::Color::toString() now can return color name 2022-12-05 22:08:58 +03:00
8e744249de Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-12-05 19:16:56 +03:00
cf5284a244 color collection, now only CSS colors
PIVariantTypes::Color from/to string (with CSS names)
2022-12-05 19:16:48 +03:00
74c20c37b7 picloud_test build fix 2022-12-04 18:30:23 +03:00
b25ecf42fb PIValueTreeConversions text, options
PIVariant fixes
2022-12-04 18:27:54 +03:00
5bb9477b5b PIVariant string conversions, PIDateTime::fromString 2022-11-30 22:40:28 +03:00
a27353d42d PIValueTreeConversions start 2022-11-29 20:44:46 +03:00
1327e46f61 PIVariant and PIValueTree changes 2022-11-29 18:08:06 +03:00
a516acbd44 PIValueTree 2022-11-29 09:17:19 +03:00
d3d2b4281c PIP_ADD_COUNTER now almost unique across different cpp
add PIValueTree
2022-11-28 14:41:12 +03:00
ab0b6a7649 remove debug 2022-11-27 12:44:19 +03:00
6e13ee173e PIVariant::fromType() methods 2022-11-27 12:40:31 +03:00
a786c928e0 PIVariant custom casts works 2022-11-27 12:13:11 +03:00
f52fc5332c PIVariant add typeID, optimization, macros simplify and change custom logic to ID 2022-11-27 11:03:32 +03:00
dc6fbbf7ec folders 2022-11-25 21:35:39 +03:00
a2256a3872 PIString::simplified 2022-11-15 17:55:55 +03:00
d45996af28 "FFTW Create plan" remove 2022-11-14 21:29:01 +03:00
05dcbca894 PIBinaryStream patches 2022-11-14 12:31:20 +03:00
57ed40912d piDeleteAll and piDeleteAllAndClear 2022-11-13 22:55:10 +03:00
46751ab977 missing include 2022-11-12 13:38:07 +03:00
e9128771db version 3.6.0
another fixes in PIEthernet
remove PIThread::interrupt()
piwaitevent patches
2022-11-12 13:31:26 +03:00
Бычков Андрей
7bbffef237 version and remove debug 2022-11-11 16:26:11 +03:00
Бычков Андрей
cb59017ebb PICloud many important fixes 2022-11-11 16:18:05 +03:00
ec8fbcb112 cloud 2022-11-10 19:37:01 +03:00
4c909e692a Merge pull request 'thread' (#170) from thread into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/170
2022-11-10 19:02:42 +03:00
Бычков Андрей
cfc9ed131a Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-10 19:01:52 +03:00
Бычков Андрей
39d81dd23b PICloudServer don't delete clients 2022-11-10 19:01:28 +03:00
56fd6b921e version 3.5.0 2022-11-10 16:16:57 +03:00
0fed454bb7 Merge pull request 'thread' (#169) from thread into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/169
2022-11-10 16:16:08 +03:00
cbac9f4253 PITimerImp_RT 2022-11-10 15:44:35 +03:00
Бычков Андрей
d46f1a137a PITimer remove wait in stop, waitForFinish 2022-11-10 15:26:19 +03:00
3d7e845213 Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-10 15:03:59 +03:00
e9a7eaa276 fixes 2022-11-10 15:03:51 +03:00
Бычков Андрей
e6a5010023 remove debug picout from cloud 2022-11-10 14:25:57 +03:00
4994d0bf66 condvar fixes 2022-11-10 14:11:40 +03:00
Бычков Андрей
15a9d68a87 Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-10 14:08:57 +03:00
Бычков Андрей
16c09ae6e9 PIEthernet atomic connected exchange 2022-11-10 14:08:42 +03:00
702d1642e0 PITimer thread imp changed from PIWaitEvent to PIConditionalVariable 2022-11-10 13:47:57 +03:00
d34374d4e0 missing 2022-11-10 12:29:49 +03:00
398d760ba9 PIObject::deleteLater important fix
PIWaitEvent::sleep() method
PITimer thread imp wait optimization, migrate to interruptable sleeps
2022-11-10 12:26:08 +03:00
Бычков Андрей
d9eac06749 pithread, pitimer stop, stopAndWait 2022-11-09 17:17:21 +03:00
Бычков Андрей
f9c1ef5ba4 Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-09 17:04:28 +03:00
Бычков Андрей
8738043dce some PICloud and PIEthernet fixes 2022-11-09 17:04:13 +03:00
db5c4dcf3f PIThread::stopAndWait 2022-11-09 17:02:28 +03:00
d3dd3fb32b blocking PIEthernet write works 2022-11-08 17:34:06 +03:00
Бычков Андрей
21fa3baf4e убрал лишнее в PICloudServer 2022-11-08 16:37:10 +03:00
Бычков Андрей
b17510218b some fix for PICloudServer 2022-11-08 15:25:27 +03:00
Бычков Андрей
897f03f3d0 some fixes for picloud, but still not working correctly 2022-11-08 14:43:52 +03:00
Бычков Андрей
36ff427e0d Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-08 10:53:43 +03:00
Бычков Андрей
2e1179e2fa Merge branch 'master' of https://git.shs.tools/SHS/pip into thread 2022-11-08 10:53:30 +03:00
fffaf0726d CAN adopted, Linux work 2022-11-07 18:07:26 +03:00
6da1ec5acf Merge branch 'thread' of https://git.shs.tools/SHS/pip into thread 2022-11-07 17:50:52 +03:00
16a8d37a8f Merge branch 'master' of https://git.shs.tools/SHS/pip into thread 2022-11-07 17:50:06 +03:00
Бычков Андрей
93a1bf4f6d some unsuccessfull fixes for picloud 2022-11-07 17:32:10 +03:00
Бычков Андрей
f08a07cab0 небольшая чистка и улучшение кода, попытка исправить picloud 2022-11-07 17:16:27 +03:00
8a5e72c723 migrate to async IO model
new PIIODevice::interrupt() virtual method
new PIWaitEvent private class
PIEthernet and PISerial basically tested on Windows and Linux
2022-11-05 23:43:07 +03:00
2163deb7ea PICodeParser entities visibility, check pip_cmg stream operators for public and global visibility 2022-11-01 14:54:53 +03:00
4219372e68 PIString::fromUTF8 BOM support 2022-11-01 14:29:07 +03:00
e48d0ebaab linux signal 2022-11-01 09:38:27 +03:00
591c92b4bb ready to test 2022-11-01 09:17:24 +03:00
6e81a419fb start move to interruption of blocking calls, PIThread and PIEthernet 2022-11-01 00:02:44 +03:00
ca403ca2c7 PIDiagnostics EPIC fix 2022-10-27 21:14:55 +03:00
e46cfdc4bd more precise using PIIODevice::reading_now flag, Warning! one should use it manually now
small enum fix for pip_cmg
2022-10-27 20:58:43 +03:00
609ff8e9c8 piserial should be fixed 2022-10-24 10:55:25 +03:00
ea0df21726 Merge pull request 'piethernet threaded connect fix, small brush of PIIODevice' (#168) from piiodevice_fix into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/168
2022-10-23 21:38:35 +03:00
3a5050b028 piethernet threaded connect fix, small brush of PIIODevice 2022-10-23 21:38:10 +03:00
2cf561767f Merge pull request 'piiodevice_fix' (#167) from piiodevice_fix into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/167
2022-10-23 19:33:41 +03:00
638f0e0181 PIIODevice remove init
picloud dispatcher fix
2022-10-23 19:22:36 +03:00
359c7816bc picloud 2022-10-23 18:48:28 +03:00
9438ab4e53 PIIODevice threaded read refactoring 2022-10-23 16:02:09 +03:00
e5777dde6c version 3.3.0 2022-10-01 10:53:09 +03:00
3c7e117661 PIJSON doc and << operator 2022-09-30 21:09:57 +03:00
0f48c206c3 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-09-30 20:28:03 +03:00
4a7f009cc6 doc 2022-09-30 20:27:58 +03:00
001812f3ce Merge pull request 'some code style' (#166) from json into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/166
2022-09-30 20:27:03 +03:00
Бычков Андрей
bf87f631f0 some code style 2022-09-30 13:58:43 +03:00
44876836c5 PIJSON improvements and doc reference 2022-09-28 18:08:19 +03:00
2d2f6b254b add PIJSON, yet without doc 2022-09-26 17:49:58 +03:00
858b54ce64 pistring::toFloat/Double/LDouble precise fixes 2022-09-19 15:20:24 +03:00
38840c5b7d version 3.2.0 2022-09-18 12:36:09 +03:00
499ee386a7 PIString::toFloat/Double/LDouble own fast implementation (. and , equivalent)
PICout ldouble support
PIEthernet small optimization
2022-09-17 17:53:58 +03:00
Бычков Андрей
eddef26b5e doc PIMap PIStack PIQueue done 2022-09-02 09:44:47 +03:00
Бычков Андрей
db3de9904a pimap some doc 2022-08-30 18:15:13 +03:00
Бычков Андрей
3511fee459 pimap some doc 2022-08-30 17:49:09 +03:00
Бычков Андрей
5a1a381a32 containers doc 2022-08-29 18:32:55 +03:00
Бычков Андрей
1bc9f5ed19 PIVector and PIDeque takeRange 2022-08-25 17:35:49 +03:00
Бычков Андрей
8370351ff3 add doc to previous commit 2022-08-24 17:33:00 +03:00
Бычков Андрей
952020a3e2 PIVector and PIDeque: split and splitBySize 2022-08-24 17:28:48 +03:00
Бычков Андрей
b35ec1f30a PIVector and PIDeque some code clean 2022-08-23 16:47:33 +03:00
443eeed38b Merge pull request 'PIDeque optimize and bugfix' (#165) from deque2 into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/165
2022-08-23 10:30:05 +03:00
d1abfe5213 Merge pull request 'PIVector some optimize code' (#164) from vector into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/164
2022-08-22 20:18:08 +03:00
Бычков Андрей
29e34bdd60 cmake generate right project tree 2022-08-22 18:44:18 +03:00
Бычков Андрей
4635e9ba4f insert optimize 2022-08-22 17:47:45 +03:00
Бычков Андрей
49e553c551 PIDeque optimize and bugfix 2022-08-22 15:59:25 +03:00
1abcf06bf6 PIVector some optimize code 2022-08-16 22:20:04 +03:00
2550f76376 return move-assignment vector optimization 2022-08-16 20:26:42 +03:00
24da7aa644 doc core reference done 2022-08-15 19:35:49 +03:00
494faf862b some doc 2022-08-15 11:43:27 +03:00
67561636e5 return move-assignment dequeue optimization 2022-08-12 23:53:22 +03:00
Бычков Андрей
00f7a24d54 new caontainers functions
atWhere()
lastAtWhere()
contains(v)
filter(), map(), reduce(), forEach() indexed and reverse variants
fix PIDeque reverse for
fix insert with move of complex type potential segfault
2022-08-12 18:14:55 +03:00
Бычков Андрей
f07f814b08 platformio_pre.py 2022-08-11 11:40:49 +03:00
fed2c5991d version 3.0.0_rc 2022-08-10 23:44:26 +03:00
ed888324b2 override 2022-08-10 23:34:11 +03:00
79efd9e15d clang fix 2022-08-10 23:23:23 +03:00
Бычков Андрей
1acd29e474 platformio_pre.py fix for new cmake macros 2022-08-10 16:37:28 +03:00
Бычков Андрей
cd7af5e9b7 remove pimap.cpp 2022-08-10 15:14:47 +03:00
Бычков Андрей
adef5b6781 PIMap some doc 2022-08-09 15:54:53 +03:00
Бычков Андрей
2e9acdb1ba убрал установку лишних инклюдов 2022-08-09 12:31:41 +03:00
f0fee0d78f mispell 2022-08-08 21:09:47 +03:00
Бычков Андрей
60f4db61eb Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-08-08 17:14:21 +03:00
Бычков Андрей
724a2dffcf picout and clean 2022-08-08 16:44:37 +03:00
616b384ad6 Merge pull request 'cmake refactoring' (#104) from cmake_refactor into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/104
2022-08-08 16:43:44 +03:00
8abc9777cc cmake refactoring 2022-08-08 15:41:01 +03:00
420 changed files with 54774 additions and 32202 deletions

224
.clang-format Normal file
View File

@@ -0,0 +1,224 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: true
AcrossEmptyLines: false
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: true
AlignCompound: false
PadOperators: true
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: CurrentLine
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- piForeach
- piForeachC
- piForeachR
- piForeachRC
- piForeachCR
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentExternBlock: NoIndent
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: Wrapped
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
MacroBlockBegin: "PRIVATE_DEFINITION_START|STATIC_INITIALIZER_BEGIN"
MacroBlockEnd: "PRIVATE_DEFINITION_END|STATIC_INITIALIZER_END"
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Middle
PPIndentWidth: 2
ReferenceAlignment: Middle
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatementsExceptControlMacros
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: false
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: false
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Both
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: After
Standard: c++11
StatementAttributeLikeMacros:
- Q_EMIT
- PIMETA
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
- PRIVATE_DECLARATION
- NO_COPY_CLASS
- FOREVER_WAIT
- WAIT_FOREVER
TabWidth: 4
UseCRLF: false
UseTab: AlignWithSpaces
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
- PIMETA
...

6
.editorconfig Normal file
View File

@@ -0,0 +1,6 @@
root = true
[*.{h,c,cpp}]
charset = utf-8
indent_style = tab
tab_width = 4

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@
_unsused _unsused
CMakeLists.txt.user* CMakeLists.txt.user*
/include /include
/release

View File

@@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip) project(PIP)
set(pip_MAJOR 2) set(PIP_MAJOR 4)
set(pip_MINOR 99) set(PIP_MINOR 7)
set(pip_REVISION 0) set(PIP_REVISION 0)
set(pip_SUFFIX ) set(PIP_SUFFIX )
set(pip_COMPANY SHS) set(PIP_COMPANY SHS)
set(pip_DOMAIN org.SHS) set(PIP_DOMAIN org.SHS)
set(GIT_CMAKE_DIR) set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT) if (NOT DEFINED SHSTKPROJECT)
@@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE) project(cmake-download NONE)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(cmake ExternalProject_Add(cmake
GIT_REPOSITORY https://git.shs.tools/SHS/cmake.git GIT_REPOSITORY https://git.shstk.ru/SHS/cmake.git
GIT_TAG \"origin/master\" GIT_TAG \"origin/master\"
GIT_CONFIG \"advice.detachedHead=false\" GIT_CONFIG \"advice.detachedHead=false\"
SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\" SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
@@ -53,7 +53,8 @@ include(CheckFunctionExists)
include(PIPMacros) include(PIPMacros)
include(SHSTKMacros) include(SHSTKMacros)
shstk_begin_project(pip PIP) shstk_begin_project(PIP)
set(PIP_VERSION "${PIP_VERSION}" CACHE STRING "")
set(_ICU_DEFAULT OFF) set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE)) if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
@@ -61,7 +62,6 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif() endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "") set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
# Options # Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT}) option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF) option(STD_IOSTREAM "Building with std iostream operators support" OFF)
@@ -72,6 +72,13 @@ set(PIP_UTILS 1)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
shstk_is_parent_exists(_pe)
if (_pe)
set(BUILDING_pip 1 PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}")
endif()
# Basic # Basic
set(PIP_MODULES) set(PIP_MODULES)
@@ -84,9 +91,11 @@ set(PIP_UTILS_LIST)
set(PIP_TESTS_LIST) set(PIP_TESTS_LIST)
set(PIP_EXPORTS) set(PIP_EXPORTS)
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;cloud;lua") set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_client;http_server")
foreach(_m ${PIP_SRC_MODULES}) foreach(_m ${PIP_SRC_MODULES})
set(PIP_MSG_${_m} "no") set(PIP_MSG_${_m} "no")
string(TOUPPER "${_m}" _mu)
option(PIP_BUILD_${_mu} "Build \"${_m}\" module" ON)
endforeach() endforeach()
macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG) macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
@@ -96,7 +105,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
set(CRES) set(CRES)
file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c") file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c")
file(GLOB_RECURSE HS "libs/${NAME}/*.h") file(GLOB_RECURSE HS "libs/${NAME}/*.h")
file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h") file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h" "libs/${NAME}/3rd/*.h")
file(GLOB_RECURSE RES "libs/${NAME}/*.conf") file(GLOB_RECURSE RES "libs/${NAME}/*.conf")
if (NOT "x${PHS}" STREQUAL "x") if (NOT "x${PHS}" STREQUAL "x")
list(REMOVE_ITEM HS ${PHS}) list(REMOVE_ITEM HS ${PHS})
@@ -105,9 +114,14 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c") file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c")
list(APPEND CPPS ${ASRC}) list(APPEND CPPS ${ASRC})
endif() endif()
#message("${NAME} HS = ${HS}")
list(APPEND HDRS ${HS}) list(APPEND HDRS ${HS})
list(APPEND PHDRS ${PHS}) list(APPEND PHDRS ${PHS})
if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
else()
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${CPPS} ${HS} ${PHS})
endif()
set(_target "pip_${NAME}") set(_target "pip_${NAME}")
set(_libs "${LIBS}") set(_libs "${LIBS}")
if ("${NAME}" STREQUAL "main") if ("${NAME}" STREQUAL "main")
@@ -118,11 +132,11 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
string(TOUPPER "${_target}" DEF_NAME) string(TOUPPER "${_target}" DEF_NAME)
set(PIP_MSG_${NAME} "yes${MSG}") set(PIP_MSG_${NAME} "yes${MSG}")
import_version(${_target} pip) import_version(${_target} PIP)
set_deploy_property(${_target} ${pip_LIB_TYPE} set_deploy_property(${_target} ${PIP_LIB_TYPE}
LABEL "${LABEL}" LABEL "${LABEL}"
FULLNAME "${pip_DOMAIN}.${_target}" FULLNAME "${PIP_DOMAIN}.${_target}"
COMPANY "${pip_COMPANY}" COMPANY "${PIP_COMPANY}"
INFO "Platform-Independent Primitives") INFO "Platform-Independent Primitives")
make_rc(${_target} _RC) make_rc(${_target} _RC)
@@ -139,7 +153,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
pip_resources(CRES "${RES}") pip_resources(CRES "${RES}")
endif() endif()
add_definitions(-D${DEF_NAME}) add_definitions(-D${DEF_NAME})
add_library(${_target} ${pip_LIB_TYPE} ${CPPS} ${CRES} ${_RC}) add_library(${_target} ${PIP_LIB_TYPE} ${CPPS} ${CRES} ${_RC} ${HS} ${PHS})
target_include_directories(${_target} PUBLIC ${PIP_INCLUDES}) target_include_directories(${_target} PUBLIC ${PIP_INCLUDES})
if (NOT "x${RES}" STREQUAL "x") if (NOT "x${RES}" STREQUAL "x")
add_dependencies(${_target} pip_rc) add_dependencies(${_target} pip_rc)
@@ -171,10 +185,12 @@ if (NOT DEFINED PIP_CMG)
if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM)) if (CMAKE_CROSSCOMPILING OR (DEFINED ANDROID_PLATFORM))
set(PIP_CMG "pip_cmg") set(PIP_CMG "pip_cmg")
set(PIP_RC "pip_rc") set(PIP_RC "pip_rc")
set(PIP_TR "pip_tr")
set(PIP_DEPLOY_TOOL "deploy_tool") set(PIP_DEPLOY_TOOL "deploy_tool")
else() else()
set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg") set(PIP_CMG "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator/pip_cmg")
set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc") set(PIP_RC "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler/pip_rc")
set(PIP_TR "${CMAKE_CURRENT_BINARY_DIR}/utils/translator/pip_tr")
set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool") set(PIP_DEPLOY_TOOL "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool/deploy_tool")
endif() endif()
endif() endif()
@@ -234,26 +250,11 @@ if(PIP_MATH_YN)
add_definitions(-DPIP_MATH_YN) add_definitions(-DPIP_MATH_YN)
endif() endif()
# Check if RT timers exists
set(CMAKE_REQUIRED_INCLUDES time.h)
set(CMAKE_REQUIRED_LIBRARIES )
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT PIP_FREERTOS))
list(APPEND LIBS_MAIN rt)
set(CMAKE_REQUIRED_LIBRARIES rt)
endif()
CHECK_FUNCTION_EXISTS(timer_create PIP_TIMER_RT_0)
CHECK_FUNCTION_EXISTS(timer_settime PIP_TIMER_RT_1)
CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2)
# Check if build debug version # Check if build debug version
if (CMAKE_BUILD_TYPE MATCHES Debug) if (PIP_BUILD_DEBUG)
set(PIP_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
add_definitions(-DPIP_DEBUG) add_definitions(-DPIP_DEBUG)
else() else()
set(PIP_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif() endif()
@@ -281,9 +282,14 @@ endif()
# Check if ICU used for PIString and PIChar # Check if ICU used for PIString and PIChar
set(PIP_ICU "no") set(PIP_ICU "no")
if(ICU) if(ICU)
pip_find_lib(icuuc)
if (icuuc_FOUND)
set(PIP_ICU "yes") set(PIP_ICU "yes")
add_definitions(-DPIP_ICU) add_definitions(-DPIP_ICU)
list(APPEND LIBS_MAIN icuuc) list(APPEND LIBS_MAIN icuuc)
else()
message(STATUS "Warning: ICU requested, but not found. Build without ICU")
endif()
endif() endif()
@@ -307,15 +313,6 @@ list(APPEND HDRS ${_PIP_DEFS_FILE})
#message("${_PIP_DEFS_CHANGED}") #message("${_PIP_DEFS_CHANGED}")
# Check if RT timers exists
if(PIP_TIMER_RT_0 AND PIP_TIMER_RT_1 AND PIP_TIMER_RT_2)
set(PIP_TIMERS "Thread, ThreadRT, Pool")
add_definitions(-DPIP_TIMER_RT)
else()
set(PIP_TIMERS "Thread, Pool")
endif()
# Add main library # Add main library
if(APPLE) if(APPLE)
@@ -326,6 +323,7 @@ if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include") #message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include") #message("${ANDROID_NDK}/sysroot/usr/include")
endif() endif()
if(NOT PIP_FREERTOS) if(NOT PIP_FREERTOS)
if(WIN32) if(WIN32)
if(${C_COMPILER} STREQUAL "cl.exe") if(${C_COMPILER} STREQUAL "cl.exe")
@@ -339,6 +337,9 @@ else()
else() else()
if (NOT DEFINED ANDROID_PLATFORM) if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND LIBS_MAIN pthread util) list(APPEND LIBS_MAIN pthread util)
if (NOT APPLE)
list(APPEND LIBS_MAIN rt)
endif()
endif() endif()
endif() endif()
endif() endif()
@@ -369,6 +370,8 @@ pip_module(main "${LIBS_MAIN}" "PIP main library" "" "" "")
generate_export_header(pip) generate_export_header(pip)
list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h") list(APPEND HDRS "${CMAKE_CURRENT_BINARY_DIR}/pip_export.h")
file(GLOB_RECURSE _RM_HDRS "libs/main/digest/3rd/*.h")
list(REMOVE_ITEM HDRS ${_RM_HDRS})
foreach(_m ${PIP_SRC_MODULES}) foreach(_m ${PIP_SRC_MODULES})
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS) set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_${_m}_EXPORTS)
generate_export_header(pip BASE_NAME "pip_${_m}") generate_export_header(pip BASE_NAME "pip_${_m}")
@@ -376,33 +379,52 @@ foreach(_m ${PIP_SRC_MODULES})
endforeach() endforeach()
set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS) set_target_properties(pip PROPERTIES DEFINE_SYMBOL pip_EXPORTS)
# Override containers minimum bytes allocation
if(NOT "x${PIP_CONTAINERS_MIN_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MIN_ALLOC=${PIP_CONTAINERS_MIN_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MIN_ALLOC = ${PIP_CONTAINERS_MIN_ALLOC}")
endif()
# Override containers maximum bytes for power of two expansion, may be bytes or X_KiB, or X_MiB
if(NOT "x${PIP_CONTAINERS_MAX_POT_ALLOC}" STREQUAL "x")
target_compile_definitions(pip PRIVATE "-DPIP_CONTAINERS_MAX_POT_ALLOC=${PIP_CONTAINERS_MAX_POT_ALLOC}")
message(STATUS "Attention: Override PIP_CONTAINERS_MAX_POT_ALLOC = ${PIP_CONTAINERS_MAX_POT_ALLOC}")
endif()
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
if (NOT PIP_FREERTOS) if (NOT PIP_FREERTOS)
if (PIP_BUILD_CONSOLE)
pip_module(console "" "PIP console support" "" "" "") pip_module(console "" "PIP console support" "" "" "")
endif()
if (PIP_BUILD_USB)
pip_find_lib(usb) pip_find_lib(usb)
if(usb_FOUND) if(usb_FOUND)
pip_module(usb "usb" "PIP usb support" "" "" "") pip_module(usb "usb" "PIP usb support" "" "" "")
endif() endif()
endif()
if (PIP_BUILD_COMPRESS)
pip_find_lib(zlib NAMES z zlib) pip_find_lib(zlib NAMES z zlib)
if(zlib_FOUND) if(zlib_FOUND)
pip_module(compress "zlib" "PIP compression support" "" "" "") pip_module(compress "zlib" "PIP compression support" "" "" "")
endif() endif()
pip_find_lib(sodium)
if(sodium_FOUND)
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
endif() endif()
if (PIP_BUILD_CRYPT)
pip_find_lib(sodium)
if(sodium_FOUND)
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
endif()
endif()
if (PIP_BUILD_FFTW)
# Check if PIP support fftw3 for PIFFT using in math module # Check if PIP support fftw3 for PIFFT using in math module
set(FFTW_LIB_NAME fftw3) set(FFTW_LIB_NAME fftw3)
set(FFTW_LIB_SUFFIXES "" "f" "l" "q") set(FFTW_LIB_SUFFIXES "" "f" "l" "q")
@@ -446,29 +468,34 @@ if (NOT CROSSTOOLS)
if(FFTW_LIBS) if(FFTW_LIBS)
pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "") pip_module(fftw "${FFTW_LIBS}" "PIP FFTW support" "" "" "")
endif() endif()
endif()
if (PIP_BUILD_OPENCL)
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
if(OpenCL_FOUND) if(OpenCL_FOUND)
set(_opencl_lib OpenCL::OpenCL)
if(${CMAKE_VERSION} VERSION_LESS "3.7.0")
target_link_libraries(_opencl_lib OpenCL)
endif()
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}") set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
if(APPLE) if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers") set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
endif() endif()
pip_module(opencl "${_opencl_lib}" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})") pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif()
endif() endif()
if (PIP_BUILD_IO_UTILS)
if(sodium_FOUND) if(sodium_FOUND)
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)") pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
else() else()
pip_module(io_utils "" "PIP I/O support" "" "" "") pip_module(io_utils "" "PIP I/O support" "" "" "")
endif() endif()
endif()
if (PIP_BUILD_LUA)
# Lua module # Lua module
set(_lua_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/3rd/lua") set(_lua_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/3rd/lua")
set(_lua_bri_dir "${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd") set(_lua_bri_dir "${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd")
@@ -480,27 +507,125 @@ if (NOT CROSSTOOLS)
endif() endif()
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge") list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr}) list(APPEND HDRS ${_lua_src_hdr})
endif()
if (PIP_BUILD_HTTP_SERVER)
# libmicrohttpd
pip_find_lib(microhttpd HINTS "${MINGW_LIB}")
if (microhttpd_FOUND)
set(_microhttpd_add_libs microhttpd)
if(WIN32)
if("${C_COMPILER}" STREQUAL "cl.exe")
else()
list(APPEND _microhttpd_add_libs ws2_32)
endif()
else()
list(APPEND _microhttpd_add_libs dl)
find_library(tls_lib gnutls)
if (tls_lib)
set(gnutls_FOUND TRUE)
set(gnutls_LIBRARIES "${tls_lib}")
list(APPEND _microhttpd_add_libs gnutls)
endif()
if(DEFINED ENV{QNX_HOST})
list(APPEND _microhttpd_add_libs socket)
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND _microhttpd_add_libs pthread util)
endif()
endif()
endif()
#list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
pip_module(http_server "${_microhttpd_add_libs}" "PIP HTTP server" "" "" "")
endif()
endif()
if (PIP_BUILD_HTTP_CLIENT)
# libcurl
pip_find_lib(curl HINTS "${MINGW_LIB}")
if (curl_FOUND)
pip_module(http_client curl "PIP HTTP client" "" "" "")
endif()
endif()
# Test program # Test program
if(PIP_UTILS) if(PIP_UTILS)
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp")
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp" "ccm.h" "ccm.cpp")
#target_link_libraries(pip_plugin pip) #target_link_libraries(pip_plugin pip)
if (NOT DEFINED ANDROID_PLATFORM)
if(microhttpd_FOUND AND curl_FOUND)
add_executable(pip_test "main.cpp") add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip) target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server pip_http_client)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
endif()
endif()
endif()
endif() endif()
else() else()
if (PIP_BUILD_CRYPT)
pip_module(crypt "" "PIP crypt support" "" "" "") pip_module(crypt "" "PIP crypt support" "" "" "")
endif()
if (PIP_BUILD_COMPRESS)
pip_module(compress "" "PIP compression support" "" "" "") pip_module(compress "" "PIP compression support" "" "" "")
endif()
if (PIP_BUILD_IO_UTILS)
pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)") pip_module(io_utils "pip_crypt" "PIP I/O support" "" "" " (+crypt)")
endif() endif()
endif()
endif() endif()
string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}") string(REPLACE ";" "," PIP_EXPORTS_STR "${PIP_EXPORTS}")
target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"") target_compile_definitions(pip PRIVATE "PICODE_DEFINES=\"${PIP_EXPORTS_STR}\"")
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
add_subdirectory("utils/qt_support")
add_subdirectory("utils/translator")
add_subdirectory("utils/value_tree_translator")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
# Translations
set(PIP_LANG)
if (NOT CROSSTOOLS)
# pip_translation(PIP_LANG lang/pip_ru.ts)
# add_custom_target(pip_lang SOURCES "${PIP_LANG}")
file(GLOB PIP_LANG "lang/*.btf")
endif()
# Install # Install
# Check if system or local install will be used (to system install use "-DLIB=" argument of cmake) # Check if system or local install will be used (to system install use "-DLIB=" argument of cmake)
if(NOT LOCAL) if(NOT LOCAL)
@@ -508,6 +633,9 @@ if(NOT LOCAL)
if(MINGW) if(MINGW)
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip) install(FILES ${HDRS} DESTINATION ${MINGW_INCLUDE}/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${MINGW_INCLUDE}/../share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION ${MINGW_INCLUDE}/pip)
endif() endif()
@@ -521,6 +649,7 @@ if(NOT LOCAL)
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/code_model_generator")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/resources_compiler")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool") file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/deploy_tool")
file(COPY "${STDLIB}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/utils/translator")
endif() endif()
else() else()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pip_export.h DESTINATION include)
@@ -528,6 +657,9 @@ if(NOT LOCAL)
else() else()
if (NOT CROSSTOOLS) if (NOT CROSSTOOLS)
install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) install(FILES ${HDRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/pip)
endif() endif()
@@ -543,6 +675,9 @@ else()
install(TARGETS ${PIP_MODULES} DESTINATION lib) install(TARGETS ${PIP_MODULES} DESTINATION lib)
endif() endif()
install(FILES ${HDRS} DESTINATION include/pip) install(FILES ${HDRS} DESTINATION include/pip)
if(PIP_LANG)
install(FILES ${PIP_LANG} DESTINATION share/pip/lang)
endif()
if(HDR_DIRS) if(HDR_DIRS)
install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip) install(DIRECTORY ${HDR_DIRS} DESTINATION include/pip)
endif() endif()
@@ -551,29 +686,6 @@ endif()
file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in") file(GLOB CMAKES "cmake/*.cmake" "cmake/*.in")
install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules) install(FILES ${CMAKES} DESTINATION ${CMAKE_ROOT}/Modules)
if(NOT PIP_FREERTOS)
# Auxiliary
if (NOT CROSSTOOLS)
add_subdirectory("utils/piterminal")
endif()
# Utils
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
if(sodium_FOUND)
add_subdirectory("utils/system_daemon")
add_subdirectory("utils/crypt_tool")
add_subdirectory("utils/cloud_dispatcher")
endif()
endif()
endif()
shstk_is_parent_exists(_pe) shstk_is_parent_exists(_pe)
if (_pe) if (_pe)
@@ -588,18 +700,18 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
find_package(Doxygen) find_package(Doxygen)
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
set(DOXY_DEFINES "${PIP_EXPORTS}") set(DOXY_DEFINES "${PIP_EXPORTS}")
foreach (_m "console" "usb" "compress" "crypt" "cloud" "fftw" "opencl" "io_utils" "lua") foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua" "http_server" "http_client")
string(TOUPPER "${_m}" _mdef) string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT") list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach() endforeach()
set(DOXY_PROJECT_NUMBER "${pip_VERSION}") set(DOXY_PROJECT_NUMBER "${PIP_VERSION}")
set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${pip_VERSION}\"") set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"")
set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${pip_VERSION}\"") set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"")
set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"") set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"")
set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"") set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"") set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"") set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DOMAIN "${pip_DOMAIN}.${PROJECT_NAME}.doc") set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc")
if ("x${DOC_LANG}" STREQUAL "x") if ("x${DOC_LANG}" STREQUAL "x")
set(DOXY_OUTPUT_LANGUAGE English) set(DOXY_OUTPUT_LANGUAGE English)
set(DOXY_OUTPUT_DIR en) set(DOXY_OUTPUT_DIR en)
@@ -644,10 +756,11 @@ macro(expand_to_length _out _str _len)
endmacro() endmacro()
list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES}) list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
list(REMOVE_DUPLICATES LIBS_STATUS)
message("----------PIP----------") message("----------PIP----------")
message(" Version: ${pip_VERSION} ") message(" Version: ${PIP_VERSION} ")
message(" Linkage: ${pip_LIB_TYPE_MSG}") message(" Linkage: ${PIP_LIB_TYPE_MSG}")
message(" Type : ${pip_BUILD_TYPE}") message(" Type : ${CMAKE_BUILD_TYPE}")
if (NOT LOCAL) if (NOT LOCAL)
message(" Install: \"${CMAKE_INSTALL_PREFIX}\"") message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else() else()
@@ -659,7 +772,6 @@ message("")
message(" Options:") message(" Options:")
message(" std::iostream: ${PIP_STD_IOSTREAM}") message(" std::iostream: ${PIP_STD_IOSTREAM}")
message(" ICU strings : ${PIP_ICU}") message(" ICU strings : ${PIP_ICU}")
message(" Timer types : ${PIP_TIMERS}")
message(" Introspection: ${PIP_INTROSPECTION}") message(" Introspection: ${PIP_INTROSPECTION}")
message(" Coverage : ${PIP_COVERAGE}") message(" Coverage : ${PIP_COVERAGE}")
if(INTROSPECTION) if(INTROSPECTION)

View File

@@ -33,10 +33,10 @@ You should add ${<out_var>} to your target.
## Documentation ## Documentation
[🇺🇸 Online documentation](https://shs.tools/pip/html/en/index.html) [🇺🇸 Online documentation](https://shstk.ru/pip/html/en/index.html)
[🇺🇸 Qt-help](https://shs.tools/pip/pip_en.qch) [🇺🇸 Qt-help](https://shstk.ru/pip/pip_en.qch)
[🇷🇺 Онлайн документация](https://shs.tools/pip/html/ru/index.html) [🇷🇺 Онлайн документация](https://shstk.ru/pip/html/ru/index.html)
[🇷🇺 Qt-help](https://shs.tools/pip/pip_ru.qch) [🇷🇺 Qt-help](https://shstk.ru/pip/pip_ru.qch)

View File

@@ -9,8 +9,11 @@ Create imported targets:
* PIP::FFTW * PIP::FFTW
* PIP::OpenCL * PIP::OpenCL
* PIP::IOUtils * PIP::IOUtils
* PIP::ClientServer
* PIP::Cloud * PIP::Cloud
* PIP::Lua * PIP::Lua
* PIP::HTTPClient
* PIP::HTTPServer
These targets include directories and depends on These targets include directories and depends on
main library main library
@@ -20,12 +23,12 @@ main library
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
include(SHSTKMacros) include(SHSTKMacros)
shstk_set_find_dirs(pip PIP) shstk_set_find_dirs(PIP)
set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua") set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua;http_client;http_server")
if (BUILDING_pip) if (BUILDING_PIP)
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua") #set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua;pip_http_client;pip_http_server")
#set(_bins "pip_cmg;pip_rc;deploy_tool") #set(_bins "pip_cmg;pip_rc;deploy_tool")
#get_target_property(_path pip BINARY_DIR) #get_target_property(_path pip BINARY_DIR)
#get_target_property(_path pip LIBRARY_OUTPUT_NAME) #get_target_property(_path pip LIBRARY_OUTPUT_NAME)
@@ -35,20 +38,22 @@ if (BUILDING_pip)
set(PIP_FOUND ON CACHE BOOL "") set(PIP_FOUND ON CACHE BOOL "")
else() else()
find_library(PIP_LIBRARY pip HINTS ${pip_LIBDIR}) find_library(PIP_LIBRARY pip HINTS ${PIP_LIBDIR})
foreach (_l ${__libs}) foreach (_l ${__libs})
find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${pip_LIBDIR}) find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${PIP_LIBDIR})
endforeach() endforeach()
endif() endif()
if (BUILDING_pip AND (NOT CMAKE_CROSSCOMPILING)) if (BUILDING_PIP AND (NOT CMAKE_CROSSCOMPILING))
set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "") set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "")
set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "") set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "")
set(PIP_TR "$<TARGET_FILE_DIR:pip_tr>/$<TARGET_FILE_NAME:pip_tr>" CACHE STRING "")
set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "") set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "")
else() else()
find_program(PIP_CMG pip_cmg${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG}) find_program(PIP_CMG pip_cmg${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
find_program(PIP_RC pip_rc${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG}) find_program(PIP_RC pip_rc${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
find_program(PIP_DEPLOY_TOOL deploy_tool${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG}) find_program(PIP_TR pip_tr${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
find_program(PIP_DEPLOY_TOOL deploy_tool${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
endif() endif()
if (NOT PIP_LIBRARY) if (NOT PIP_LIBRARY)
if(PIP_FIND_REQUIRED) if(PIP_FIND_REQUIRED)
@@ -58,7 +63,7 @@ if (NOT PIP_LIBRARY)
endif() endif()
set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}") set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}")
set(_PIP_ADD_LIBS_ "") set(_PIP_ADD_LIBS_ "")
if (NOT BUILDING_pip) if (NOT BUILDING_PIP)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
find_library(DL_LIBRARY dl) find_library(DL_LIBRARY dl)
list(APPEND PIP_LIBRARY ${DL_LIBRARY}) list(APPEND PIP_LIBRARY ${DL_LIBRARY})
@@ -75,9 +80,9 @@ if (NOT BUILDING_pip)
endif() endif()
endif() endif()
if (NOT BUILDING_pip) if (NOT BUILDING_PIP)
shstk_find_header(pip PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}") shstk_find_header(PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}")
set(PIP_INCLUDES "${pip_INCLUDES}" CACHE STRING "") set(PIP_INCLUDES "${PIP_INCLUDES}" CACHE STRING "")
endif() endif()
if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION) if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION)
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!") message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
@@ -90,8 +95,11 @@ set(__module_fftw FFTW )
set(__module_compress Compress ) set(__module_compress Compress )
set(__module_opencl OpenCL ) set(__module_opencl OpenCL )
set(__module_io_utils IOUtils ) set(__module_io_utils IOUtils )
set(__module_client_server ClientServer)
set(__module_cloud Cloud ) set(__module_cloud Cloud )
set(__module_lua Lua ) set(__module_lua Lua )
set(__module_http_client HTTPClient )
set(__module_http_server HTTPServer )
foreach (_l ${__libs}) foreach (_l ${__libs})
set( __inc_${_l} "") set( __inc_${_l} "")
@@ -100,13 +108,14 @@ foreach (_l ${__libs})
endforeach() endforeach()
set(__deps_io_utils "PIP::Crypt" ) set(__deps_io_utils "PIP::Crypt" )
set(__deps_client_server "PIP::IOUtils")
set(__deps_cloud "PIP::IOUtils") set(__deps_cloud "PIP::IOUtils")
if (BUILDING_pip) if (BUILDING_PIP)
if (NOT SET_TARGETS_pip) if (NOT SET_TARGETS_PIP)
set(SET_TARGETS_pip ON CACHE BOOL "") set(SET_TARGETS_PIP ON CACHE BOOL "")
#message("create aliases") #message("create aliases")
if((NOT TARGET PIP) AND PIP_LIBRARY) if((NOT TARGET PIP) AND PIP_LIBRARY)
#message("alias PIP = pip") #message("alias PIP = pip")
@@ -128,7 +137,7 @@ else()
add_library(PIP UNKNOWN IMPORTED) add_library(PIP UNKNOWN IMPORTED)
set_target_properties(PIP PROPERTIES set_target_properties(PIP PROPERTIES
IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}" IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}"
INTERFACE_INCLUDE_DIRECTORIES "${pip_INCLUDES}" INTERFACE_INCLUDE_DIRECTORIES "${PIP_INCLUDES}"
INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}") INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}")
#message("imported PIP = ${PIP_LIBRARY}") #message("imported PIP = ${PIP_LIBRARY}")
endif() endif()

View File

@@ -18,6 +18,14 @@
Generate C++ files for resource file Generate C++ files for resource file
You should add ${<out_var>} to your target You should add ${<out_var>} to your target
pip_translation(<out_var> ts_file)
Generate *.btf (binary translation file) from *.ts file
You should add ${<out_var>} to your target and then install it to somewhere
for later loading in runtime by PITranslator
]] ]]
@@ -119,3 +127,34 @@ macro(pip_resources RESULT INPUT)
VERBATIM) VERBATIM)
endmacro() endmacro()
macro(pip_translation RESULT INPUT)
#message(STATUS "src = ${CCM_SRC}")
#message(STATUS "result = ${RESULT}")
#message(STATUS "options = \"${CCM_OPTS}\"")
get_filename_component(BTF_FILENAME "${INPUT}" NAME_WE)
set(BTF_FILENAME "${BTF_FILENAME}.btf")
set(BTF_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BTF_FILENAME})
list(APPEND ${RESULT} "${BTF_OUTPUT}")
if(IS_ABSOLUTE "${INPUT}")
set(IN_FILES "${INPUT}")
else()
set(IN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
endif()
#message(STATUS "CCM = ${RESULT}")
if(NOT DEFINED PIP_DLL_DIR)
set(PIP_DLL_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
#message("PIP_TR: ${PIP_TR}")
#message("BTF_OUTPUT: ${BTF_OUTPUT}")
#message("IN_FILES: ${IN_FILES}")
#message("PIP_DLL_DIR: ${PIP_DLL_DIR}")
add_custom_command(OUTPUT ${BTF_OUTPUT}
COMMAND ${PIP_TR}
ARGS -C -o "${BTF_OUTPUT}" "${IN_FILES}"
DEPENDS ${IN_FILES}
WORKING_DIRECTORY ${PIP_DLL_DIR}
COMMENT "Generating ${BTF_FILENAME}"
VERBATIM)
endmacro()

View File

@@ -9,8 +9,14 @@ struct S {
}; };
// Operators // Operators
PIByteArray & operator <<(PIByteArray & b, const S & s) {b << s.i << s.f << s.s; return b;} PIByteArray & operator<<(PIByteArray & b, const S & s) {
PIByteArray & operator >>(PIByteArray & b, S & s) {b >> s.i >> s.f >> s.s; return b;} b << s.i << s.f << s.s;
return b;
}
PIByteArray & operator>>(PIByteArray & b, S & s) {
b >> s.i >> s.f >> s.s;
return b;
}
//! [struct] //! [struct]
//! [write] //! [write]
// Write chunk stream // Write chunk stream
@@ -22,10 +28,7 @@ PIVector<float> f;
f << -1. << 2.5 << 11.; f << -1. << 2.5 << 11.;
// write some data to empty stream // write some data to empty stream
PIChunkStream cs; PIChunkStream cs;
cs << cs.chunk(1, int(10)) cs << cs.chunk(1, int(10)) << cs.chunk(2, PIString("text")) << cs.chunk(4, f) << cs.chunk(3, s);
<< cs.chunk(2, PIString("text"))
<< cs.chunk(4, f)
<< cs.chunk(3, s);
// now you can take cs.data() and send or place it somewhere ... // now you can take cs.data() and send or place it somewhere ...
//! [write] //! [write]
//! [read] //! [read]
@@ -62,6 +65,6 @@ PIByteArray & operator >>(PIByteArray & s, S & value) {
if (!cs.extract(s)) return s; if (!cs.extract(s)) return s;
cs.readAll(); cs.readAll();
cs.get(1, value.i).get(2, value.f).get(3, value.s); cs.get(1, value.i).get(2, value.f).get(3, value.s);
return b; return s;
} }
//! [read_new] //! [read_new]

View File

@@ -18,37 +18,40 @@ inline PICout operator <<(PICout s, const PIByteArray & ba) {
} }
//! [own] //! [own]
// clang-format off
void _() { void _() {
//! [0] //! [0]
using namespace PICoutManipulators;
int a = 10, b = 32, c = 11; int a = 10, b = 32, c = 11;
piCout << a << Hex << b << Bin << c; piCout << a << Hex << b << Bin << c;
// 10 20 1011 // 10 20 1011
piCout << "this" << "is" << Green << "green" << Default << "word"; piCout << "this"
<< "is" << Green << "green" << Default << "word";
// this is green word // this is green word
PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and" << "quotes"; PICout(AddSpaces | AddNewLine | AddQuotes) << Tab << "tab and"
<< "quotes";
// "tab and" "quotes" // "tab and" "quotes"
//! [0] //! [0]
} }
// clang-format on
//! [notifier] //! [notifier]
class A: public PIObject { class A: public PIObject {
PIOBJECT(A) PIOBJECT(A)
public: public:
A() {} A() {}
EVENT_HANDLER2(void, pcf, int, id, PIString*, buff) { EVENT_HANDLER2(void, pcf, int, id, PIString *, buff) { piCout << "PICout(" << id << ") finished:" << (*buff); }
piCout << "PICout(" << id << ") finished:" << (*buff);
}
}; };
int main() { int main() {
A a; A a;
CONNECTU(PICout::Notifier::object(), finished, &a, pcf); CONNECTU(PICout::Notifier::object(), finished, &a, pcf);
PIString buffer = "my buff:"; PIString buffer = "my buff:";
PICout(&buffer, 1) << "int 10 ->" << 10 << ", time ->" << PITime::current(); int my_id = PICout::registerExternalBufferID();
PICout::withExternalBufferAndID(&buffer, my_id) << "int 10 ->" << 10 << ", time ->" << PITime::current();
return 0; return 0;
} }
// PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000) // PICout( 1 ) finished: my buff:int 10 -> 10 , time -> PITime(14:07:09:000)

View File

@@ -1,10 +1,10 @@
#include "pip.h" #include "pip.h"
//! [delimiter] //! [delimiter]
void tfunc(void * , int delim) { void tfunc(int delim) {
piCout << "tick with delimiter" << delim; piCout << "tick with delimiter" << delim;
}; };
void tfunc4(void * , int delim) { void tfunc4(int delim) {
piCout << "tick4 with delimiter" << delim; piCout << "tick4 with delimiter" << delim;
}; };
int main() { int main() {
@@ -13,8 +13,7 @@ int main() {
timer.addDelimiter(4, tfunc4); timer.addDelimiter(4, tfunc4);
timer.start(50); timer.start(50);
piMSleep(200); piMSleep(200);
timer.stop(); timer.stopAndWait();
timer.waitForFinish();
return 0; return 0;
}; };
/* Result: /* Result:
@@ -29,14 +28,14 @@ tick4 with delimiter 4
//! [delimiter] //! [delimiter]
//! [elapsed] //! [elapsed]
int main() { int main() {
PITimer timer; PITimeMeasurer tm;
piMSleep(100); piMSleep(100);
piCout << "elapsed" << timer.elapsed_m() << "ms"; piCout << "elapsed" << tm.elapsed_m() << "ms";
piMSleep(100); piMSleep(100);
piCout << "elapsed" << timer.elapsed_m() << "ms"; piCout << "elapsed" << tm.elapsed_m() << "ms";
timer.reset(); tm.reset();
piMSleep(150); piMSleep(150);
piCout << "elapsed" << timer.elapsed_s() << "s"; piCout << "elapsed" << tm.elapsed_s() << "s";
return 0; return 0;
}; };
/* Result: /* Result:
@@ -53,9 +52,9 @@ int main() {
t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0 t0 -= PISystemTime::fromSeconds(0.1); // s = 1, ns = 0
t0.sleep(); // sleep for 1 second t0.sleep(); // sleep for 1 second
PISystemTime t1; PISystemTime t1;
t0 = currentSystemTime(); t0 = PISystemTime::current();
piMSleep(500); piMSleep(500);
t1 = currentSystemTime(); t1 = PISystemTime::current();
(t1 - t0).sleep(); // sleep for 500 milliseconds (t1 - t0).sleep(); // sleep for 500 milliseconds
return 0; return 0;
}; };
@@ -64,5 +63,4 @@ int main() {
void _(){ void _(){
}; };

View File

@@ -66,7 +66,7 @@ pip_code_model(<out_var> file0 [file1 ...] [OPTIONS opt0 [opt1 ...] ] [NAME name
## Метаинформация ## Метаинформация
Метаинформация - это текстовое представление всех членов и методов структуры или класса C++. Метаинформация - это текстовое представление всех членов и методов структуры или класса C++.
Для доступа к ним используется PICodeInfo::classesInfo->value("name"), который возвращает Для доступа к ним используется PICODEINFO::classes().value("name"), который возвращает
указатель на структуру PICodeInfo::ClassInfo, содержащую всю информацию о сущности. указатель на структуру PICodeInfo::ClassInfo, содержащую всю информацию о сущности.
В любой структуре PICodeInfo есть поле "MetaMap meta", содержащее произвольные В любой структуре PICodeInfo есть поле "MetaMap meta", содержащее произвольные
@@ -90,7 +90,7 @@ enum FOV { // Поле зрения
## Перечисления ## Перечисления
Перечисления записываются отдельно, для доступа к ним используется PICodeInfo::enumsInfo->value("name"), Перечисления записываются отдельно, для доступа к ним используется PICODEINFO::enums().value("name"),
который возвращает указатель на структуру PICodeInfo::EnumInfo, содержащую всю информацию о перечеслении. который возвращает указатель на структуру PICodeInfo::EnumInfo, содержащую всю информацию о перечеслении.
## Операторы де/сериализации ## Операторы де/сериализации
@@ -290,7 +290,7 @@ C++:
... ...
PICodeInfo::EnumInfo * ei = PICodeInfo::enumsInfo->value("MyEnum", 0); PICodeInfo::EnumInfo * ei = PICODEINFO::enums().value("MyEnum", 0);
if (ei) { if (ei) {
ei->members.forEach([](const PICodeInfo::EnumeratorInfo & e){piCout << e.name << "=" << e.value;}); ei->members.forEach([](const PICodeInfo::EnumeratorInfo & e){piCout << e.name << "=" << e.value;});
} }

View File

@@ -2,6 +2,7 @@
\~russian \page iostream Поток ввода/вывода \~russian \page iostream Поток ввода/вывода
\~english \~english
\~russian \~russian
%PIBinaryStream представляет собой интерфейс бинарной сериализации. %PIBinaryStream представляет собой интерфейс бинарной сериализации.
Не может быть использован в чистом виде, только в виде миксина или Не может быть использован в чистом виде, только в виде миксина или
@@ -115,3 +116,10 @@ for (int i = 0; i < 10; ++i)
0.8 0.8
0.9 0.9
\endcode \endcode
\~english
\~russian
Если при чтении из потока не хватило данных (например, закончился массив или файл), то проверка
объекта потока на wasReadError() вернёт true. Рекомендуется делать эту проверку после чтения
данных для корректной обработки ошибки.

View File

@@ -3,19 +3,19 @@
\~english \~english
* direct output to console (\a PICout) * Direct output to console (\a PICout)
* containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet) * Containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* byte array (\a PIByteArray) * Byte array (\a PIByteArray)
* serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream) * Serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
* string (\a PIConstChars, \a PIString, \a PIStringList) * String (\a PIConstChars, \a PIString, \a PIStringList)
* base object (events and handlers) (\a PIObject) * Base object (events and handlers) (\a PIObject)
* multithreading * Multithreading
* thread (\a PIThread) * thread (\a PIThread)
* blocking (\a PIMutex, \a PISpinlock) * blocking (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
* executor (\a PIThreadPoolExecutor) * executor (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
* blocking dequeue (\a PIBlockingDequeue) * blocking dequeue (\a PIBlockingDequeue)
* timer (\a PITimer) * timer (\a PITimer)
* tiling console (with widgets) (\a PIScreen) * Tiling console (with widgets) (\a PIScreen)
* simple text rows * simple text rows
* scroll bar * scroll bar
* list * list
@@ -37,7 +37,8 @@
* peering net node (\a PIPeer) * peering net node (\a PIPeer)
* connection quality diagnotic (\a PIDiagnostics) * connection quality diagnotic (\a PIDiagnostics)
* Run-time libraries * Run-time libraries
* abstract (\a PILibrary) * external process (\a PIProcess)
* external library (\a PILibrary)
* plugin (\a PIPluginLoader) * plugin (\a PIPluginLoader)
* Mathematics * Mathematics
* complex numbers * complex numbers
@@ -49,24 +50,33 @@
* CRC checksum (\a PICRC) * CRC checksum (\a PICRC)
* Fourier transform (\a PIFFTW, \a PIFFT) * Fourier transform (\a PIFFTW, \a PIFFT)
* expression evaluator (\a PIEvaluator) * expression evaluator (\a PIEvaluator)
* Application-level
* command-line arguments parser (\a PICLI) * command-line arguments parser (\a PICLI)
* process (\a PIProcess) * system resources monitoring (\a PISystemMonitor)
* single-instance application control (\a PISingleApplication)
* high-level log (\a PILog)
* translation support (\a PITranslator)
* State machine ([By stantard](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* High-level TCP client-server
* server (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* client (\a PIClientServer::Client)
* Crypt support (\a PICrypt, \a PIAuth)
\~russian \~russian
* общение с консолью (\a PICout) * Общение с консолью (\a PICout)
* контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet) * Контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* байтовый массив (\a PIByteArray) * Байтовый массив (\a PIByteArray)
* сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream) * Сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
* строка (\a PIConstChars, \a PIString, \a PIStringList) * Строка (\a PIConstChars, \a PIString, \a PIStringList)
* базовый объект (события и обработчики) (\a PIObject) * Базовый объект (события и обработчики) (\a PIObject)
* многопоточность * Многопоточность
* поток (\a PIThread) * поток (\a PIThread)
* блокировки (\a PIMutex, \a PISpinlock) * блокировки (\a PIMutex, \a PISpinlock, \a PIConditionVariable, \a PISemaphore, \a PIReadWriteLock)
* исполнитель (\a PIThreadPoolExecutor) * исполнитель (\a PIThreadPoolExecutor, \a PIThreadPoolLoop)
* блокирующая очередь (\a PIBlockingDequeue) * блокирующая очередь (\a PIBlockingDequeue)
* таймер (\a PITimer) * таймер (\a PITimer)
* тайлинговая консоль (с виджетами) (\a PIScreen) * Тайлинговая консоль (с виджетами) (\a PIScreen)
* простой вывод строк * простой вывод строк
* скроллбар * скроллбар
* лист * лист
@@ -76,7 +86,7 @@
* прогрессбар * прогрессбар
* вывод PICout * вывод PICout
* текстовый ввод * текстовый ввод
* устройства ввода/вывода * Устройства ввода/вывода
* базовый класс (\a PIIODevice) * базовый класс (\a PIIODevice)
* файл (\a PIFile) * файл (\a PIFile)
* последовательный порт (\a PISerial) * последовательный порт (\a PISerial)
@@ -87,8 +97,9 @@
* сложное составное устройство (\a PIConnection) * сложное составное устройство (\a PIConnection)
* пиринговая сеть (\a PIPeer) * пиринговая сеть (\a PIPeer)
* диагностика качества связи (\a PIDiagnostics) * диагностика качества связи (\a PIDiagnostics)
* поддержка библиотек времени выполнения * Поддержка библиотек времени выполнения
* базовая функциональность (\a PILibrary) * внешний процесс (\a PIProcess)
* внешняя библиотека (\a PILibrary)
* плагин (\a PIPluginLoader) * плагин (\a PIPluginLoader)
* Математика * Математика
* комплексные числа * комплексные числа
@@ -100,5 +111,14 @@
* CRC контрольная сумма (\a PICRC) * CRC контрольная сумма (\a PICRC)
* преобразования Фурье (\a PIFFTW, \a PIFFT) * преобразования Фурье (\a PIFFTW, \a PIFFT)
* вычислитель выражений (\a PIEvaluator) * вычислитель выражений (\a PIEvaluator)
* Уровень приложения
* парсер аргументов командной строки (\a PICLI) * парсер аргументов командной строки (\a PICLI)
* процесс (\a PIProcess) * мониторинг ресурсов системы (\a PISystemMonitor)
* контроль одного экземпляра приложения (\a PISingleApplication)
* высокоуровневый лог (\a PILog)
* поддержка перевода (\a PITranslator)
* Машина состояний ([По стандарту](https://www.w3.org/TR/scxml/)) (\a PIStateMachine)
* Высокоуровневый TCP клиент-сервер
* сервер (\a PIClientServer::Server, \a PIClientServer::ServerClient)
* клиент (\a PIClientServer::Client)
* Поддержка шифрования (\a PICrypt, \a PIAuth)

View File

@@ -56,7 +56,7 @@ class MainClass: public PITimer {
public: public:
MainClass() {} MainClass() {}
protected: protected:
void tick(void * data, int delimiter) { void tick(int delimiter) {
piCout << "timer tick"; piCout << "timer tick";
// timer tick // timer tick
} }

View File

@@ -1,2 +1 @@
#include "pip.h" #include "pip.h"

1
lang/compile.bat Normal file
View File

@@ -0,0 +1 @@
pip_tr --Compile -o pip_ru.btf pip_ru.ts

BIN
lang/pip_ru.btf Normal file

Binary file not shown.

531
lang/pip_ru.ts Normal file
View File

@@ -0,0 +1,531 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ru">
<context>
<name>PICLI</name>
<message>
<location filename="../libs/main/application/picli.cpp" line="120"/>
<source>Arguments overflow, &quot;%1&quot; ignored</source>
<translation>Переизбыток аргументов, &quot;%1&quot; проигнорирован</translation>
</message>
</context>
<context>
<name>PIDiag</name>
<message>
<location filename="../libs/main/io_utils/pidiagnostics.cpp" line="155"/>
<source>/s</source>
<translation>/сек</translation>
</message>
</context>
<context>
<name>PIFile</name>
<message>
<location filename="../libs/main/io_devices/pifile.cpp" line="299"/>
<source>Downsize is not supported yet :-(</source>
<translation>Уменьшение размера не поддерживается</translation>
</message>
</context>
<context>
<name>PICloud</name>
<message>
<location filename="../libs/cloud/picloudtcp.cpp" line="139"/>
<source>Invalid PICloud::TCP version!</source>
<translation>Неверная версия PICloud::TCP!</translation>
</message>
<message>
<location filename="../libs/cloud/picloudserver.cpp" line="230"/>
<source>Error: buffer overflow, drop %1 bytes</source>
<translation>Ошибка: переполнение буфера, отброшено %1 байт</translation>
</message>
<message>
<location filename="../libs/cloud/picloudserver.cpp" line="251"/>
<source>Warning: reject client with duplicated ID</source>
<translation>Предупреждение: отклонен клиент с дублирующимся ID</translation>
</message>
</context>
<context>
<name>PICrypt</name>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="205"/>
<source>internal error: bad hash size</source>
<translation>внутренняя ошибка: плохой размер хэша</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="39"/>
<source>Error while initialize sodium!</source>
<translation>Ошибка инициализации sodium!</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="209"/>
<source>invalid key size %1, should be %2, filled with zeros</source>
<translation>неверный размер ключа %1, должен быть %2, заполненный нулями</translation>
</message>
<message>
<location filename="../libs/crypt/picrypt.cpp" line="29"/>
<source>Warning: PICrypt is disabled, to enable install sodium library and rebuild pip</source>
<translation>Предупреждение: PICrypt неактивен, для активации установите библиотеку sodium и пересоберите PIP</translation>
</message>
</context>
<context>
<name>PIBinLog</name>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="436"/>
<source>Read record error</source>
<translation>Ошибка чтения записи</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="432"/>
<source>End of BinLog file</source>
<translation>Конец BinLog файла</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="776"/>
<source>Error, can&apos;t open &quot;%1&quot;</source>
<translation>Ошибка, невозможно открыть &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="262"/>
<source>Creating directory &quot;%1&quot;</source>
<translation>Создание директории &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="785"/>
<source>Error, can&apos;t create &quot;%1&quot;</source>
<translation>Ошибка, невозможно создать &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="140"/>
<source>Error: File is null &quot;%1&quot;</source>
<translation>Ошибка, Файл пуст &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="789"/>
<source>Start join binlogs to &quot;%1&quot;</source>
<translation>Начало слияния логов в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="514"/>
<source>BinLogFile has too old verion</source>
<translation>BinLogFile очень старой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="513"/>
<source>BinLogFile has invalid version</source>
<translation>BinLogFile неверной версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="515"/>
<source>BinLogFile has too new version</source>
<translation>BinLogFile очень новой версии</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="386"/>
<source>Can&apos;t find record with id = %1</source>
<translation>Невозможно найти запись с ID = %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="803"/>
<source>Error, can&apos;t write to file &quot;%1&quot;</source>
<translation>Ошибка, невозможно записать в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="126"/>
<source>Error: Can&apos;t open file &quot;%1&quot;: %2</source>
<translation>Ошибка: Невозможно открыть файл &quot;%1&quot;: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="149"/>
<source>Warning: Empty BinLog file &quot;%1&quot;</source>
<translation>Предупреждение: Пустой BinLog файл &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="825"/>
<source>Finish join binlogs, total time %1</source>
<translation>Завершение слияния логов, общее время %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="440"/>
<source>too small read buffer: %1, data size: %2</source>
<translation>слишком маленький буфер: %1, размер данных: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="133"/>
<source>Error: Can&apos;t write binlog file header &quot;%1&quot;</source>
<translation>Ошибка: Невозможно записать заголовок в &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="319"/>
<source>Error: can`t write with id = 0! ID must be &gt; 0</source>
<translation>Ошибка: Невозможно записать с ID = 0! ID должен быть &gt; 0</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="495"/>
<source>BinLogFile signature is corrupted or invalid file</source>
<translation>Неверный заголовок BinLogFile, либо файл поврежден</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="295"/>
<source>Can&apos;t create new file, maybe path &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно путь &quot;%1&quot; неверен</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="286"/>
<source>Can&apos;t create new file, maybe LogDir &quot;%1&quot; is invalid</source>
<translation>Невозможно создать новый файл, возможно LogDir &quot;%1&quot; неверен</translation>
</message>
<message>
<location filename="../libs/main/io_devices/pibinarylog.cpp" line="104"/>
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
</message>
</context>
<context>
<name>PIOpenCL</name>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="509"/>
<source>Error: empty range</source>
<translation>Ошибка: пустой диапазон</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="586"/>
<source>setArgValue invalid index %1</source>
<translation>setArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="616"/>
<source>bindArgValue invalid index %1</source>
<translation>bindArgValue неверный индекс %1</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="592"/>
<source>setArgValue set scalar to &quot;%1 %2&quot;</source>
<translation>setArgValue устанавливается скаляр в &quot;%1 %2&quot;</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="93"/>
<source>Error: OpenCL platforms not found!</source>
<translation>Ошибка: Платформы OpenCL не найдены!</translation>
</message>
<message>
<location filename="../libs/opencl/piopencl.cpp" line="622"/>
<source>bindArgValue set buffer to &quot;%1 %2&quot;</source>
<translation>bindArgValue устанавливается буфер в &quot;%1 %2&quot;</translation>
</message>
</context>
<context>
<name>PISerial</name>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="887"/>
<source>Read error: %1</source>
<translation>Ошибка чтения: %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="726"/>
<source>Unable to open &quot;%1&quot;: %2</source>
<translation>Невозможно открыть &quot;%1&quot;: %2</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="467"/>
<source>Warning: Custom speed %1</source>
<translation>Предупреждение: Нестандартная скорость %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="695"/>
<source>Unable to find device &quot;%1&quot;</source>
<translation>Невозможно найти устройство &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="826"/>
<source>Can`t set attributes for &quot;%1&quot;</source>
<translation>Невозможно установить атрибуты для &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="792"/>
<source>Unable to set comm state for &quot;%1&quot;</source>
<translation>Невозможно установить comm state для &quot;%1&quot;</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piserial.cpp" line="470"/>
<source>Warning: Unknown speed %1, using 115200</source>
<translation>Предупреждение: Неизвестная скорость %1, используется 115200</translation>
</message>
</context>
<context>
<name>PIString</name>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1774"/>
<source>B</source>
<translation>Б</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1794"/>
<source>EiB</source>
<translation>ЭиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1791"/>
<source>GiB</source>
<translation>ГиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1789"/>
<source>KiB</source>
<translation>КиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1790"/>
<source>MiB</source>
<translation>МиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1793"/>
<source>PiB</source>
<translation>ПиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1792"/>
<source>TiB</source>
<translation>ТиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1796"/>
<source>YiB</source>
<translation>ЙиБ</translation>
</message>
<message>
<location filename="../libs/main/text/pistring.cpp" line="1795"/>
<source>ZiB</source>
<translation>ЗиБ</translation>
</message>
</context>
<context>
<name>PIThread</name>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="667"/>
<source>Warning, terminate!</source>
<translation>Предупреждение, прекращение потока!</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="785"/>
<source>Error: Can`t start new thread: %1</source>
<translation>Ошибка: Невозможно начать новый поток: %1</translation>
</message>
<message>
<location filename="../libs/main/thread/pithread.cpp" line="572"/>
<source>[PIThread &quot;%1&quot;] Warning, terminate on destructor!</source>
<translation>[PIThread &quot;%1&quot;] Предупреждение, прекращение в деструкторе!</translation>
</message>
</context>
<context>
<name>PIProcess</name>
<message>
<location filename="../libs/main/system/piprocess.cpp" line="200"/>
<source>&quot;CreateProcess&quot; error: %1</source>
<translation>Ошибка &quot;CreateProcess&quot;: %1</translation>
</message>
</context>
<context>
<name>PIVariant</name>
<message>
<location filename="../libs/main/types/pivariant.cpp" line="415"/>
<source>Can`t initialize PIVariant from unregistered type &quot;%1&quot;!</source>
<translation>Невозможно инициализировать PIVariant из незарегистрированного типа &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/types/pivariant.cpp" line="393"/>
<source>Can`t initialize PIVariant from unregistered typeID &quot;%1&quot;!</source>
<translation>Невозможно инициализировать PIVariant из незарегистрированного ID типа &quot;%1&quot;!</translation>
</message>
</context>
<context>
<name>PICompress</name>
<message>
<location filename="../libs/compress/picompress.cpp" line="63"/>
<source>Error: invalid input</source>
<translation>Ошибка: неверный вход</translation>
</message>
<message>
<location filename="../libs/compress/picompress.cpp" line="74"/>
<source>Error: invalid input or not enought memory</source>
<translation>Ошибка: неверный вход или недостаточно памяти</translation>
</message>
<message>
<location filename="../libs/compress/picompress.cpp" line="80"/>
<source>Warning: PICompress is disabled, to enable install zlib library and build pip_compress library</source>
<translation>Предупреждение: PICompress неактивен, для активации установите библиотеку zlib и пересоберите PIP</translation>
</message>
</context>
<context>
<name>PIEthernet</name>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1233"/>
<source>Can`t get interfaces: %1</source>
<translation>Невозможно получить интерфейсы: %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="903"/>
<source>Can`t accept new connection, %1</source>
<translation>Невозможно принять новое соединение, %1</translation>
</message>
<message>
<location filename="../libs/main/io_devices/piethernet.cpp" line="1096"/>
<source>Error allocating memory needed to call GetAdaptersInfo</source>
<translation>Ошибка выделения памяти для вызова GetAdaptersInfo</translation>
</message>
</context>
<context>
<name>PIIODevice</name>
<message>
<location filename="../libs/main/io_devices/piiodevice.cpp" line="226"/>
<source>Error: Device is running after destructor!</source>
<translation>Ошибка: Устройство в поточном выполнении после деструктора!</translation>
</message>
</context>
<context>
<name>PIIOString</name>
<message>
<location filename="../libs/main/io_devices/piiostring.cpp" line="54"/>
<source>Error: ReadWrite mode not supported, use WriteOnly or ReadOnly</source>
<translation>Ошибка: Режим ReadWrite не поддерживается, используйте WriteOnly или ReadOnly</translation>
</message>
</context>
<context>
<name>PIConnection</name>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
<source>Error,</source>
<translation>Ошибка,</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="922"/>
<source>Null Device!</source>
<translation>Нет Устройства!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="913"/>
<source>No such device &quot;%1&quot;!</source>
<translation>Нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="903"/>
<source>No such full path &quot;%1&quot;!</source>
<translation>Нет полного пути &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="927"/>
<source>Device &quot;%1&quot; can`t write!</source>
<translation>Устройство &quot;%1&quot; не может писать!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="986"/>
<source>Error: can`t create device &quot;%1&quot;!</source>
<translation>Ошибка: Невозможно создать устройство &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="242"/>
<source>&quot;addFilter&quot; error: no such device &quot;%1&quot;!</source>
<translation>ошибка &quot;addFilter&quot;: нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="743"/>
<source>&quot;addSender&quot; error: no such device &quot;%1&quot;!</source>
<translation>ошибка &quot;addSender&quot;: нет устройства &quot;%1&quot;!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="146"/>
<source>names assigned to both devices and filters!</source>
<translation>имена назначены одновременно устройствам и фильтрам!</translation>
</message>
<message>
<location filename="../libs/main/io_utils/piconnection.cpp" line="512"/>
<source>&quot;addFilter&quot; error: no such device or filter &quot;%1&quot;!</source>
<translation>ошибка &quot;addFilter&quot;: нет устройства или фильтра &quot;%1&quot;!</translation>
</message>
</context>
<context>
<name>PISystemTime</name>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="335"/>
<source>fromSystemTime() Warning: null frequency</source>
<translation>fromSystemTime() Предупреждение: нулевая частота</translation>
</message>
<message>
<location filename="../libs/main/types/pisystemtime.cpp" line="325"/>
<source>toSystemTime() Warning: invalid hertz: %1</source>
<translation>toSystemTime() Предупреждение: неверная частота: %1</translation>
</message>
</context>
<context>
<name>PIEthUtilBase</name>
<message>
<location filename="../libs/io_utils/piethutilbase.cpp" line="91"/>
<source>PICrypt wasn`t built!</source>
<translation>PICrypt не был собран!</translation>
</message>
</context>
<context>
<name>PIBaseTransfer</name>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="125"/>
<source>invalid CRC</source>
<translation>неверная CRC</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="219"/>
<source>restart receive</source>
<translation>перезапуск приема</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="176"/>
<source>invalid reply id</source>
<translation>неверный ID ответа</translation>
</message>
<message>
<location filename="../libs/main/io_utils/pibasetransfer.cpp" line="102"/>
<source>invalid packet signature</source>
<translation>неверная подпись пакета</translation>
</message>
</context>
<context>
<name>PIClientServer</name>
<message>
<location filename="../libs/client_server/piclientserver_server.cpp" line="39"/>
<source>ClientFactory returns nullptr!</source>
<translation>ClientFactory вернул nullptr!</translation>
</message>
<message>
<location filename="../libs/client_server/piclientserver_server.cpp" line="33"/>
<source>Server::newConnection overflow clients count</source>
<translation>Server::newConnection переполнение количества клиентов</translation>
</message>
</context>
<context>
<name>PIStateMachine</name>
<message>
<location filename="../libs/main/state_machine/pistatemachine_state.cpp" line="111"/>
<source>Error: &quot;%1&quot; no initial state!</source>
<translation>Ошибка: &quot;%1&quot; без стартового состояния!</translation>
</message>
</context>
<context>
<name>PIStreamPacker</name>
<message>
<location filename="../libs/io_utils/pistreampacker.cpp" line="218"/>
<source>Warning! Not recommended to use with non-reliable device</source>
<translation>Предупреждение! Не рекомендуется использовать с ненадежными устройствами</translation>
</message>
</context>
<context>
<name>PISystemMonitor</name>
<message>
<location filename="../libs/main/application/pisystemmonitor.cpp" line="111"/>
<source>Can`t find process with ID = %1!</source>
<translation>Невозможно найти процесс с ID = %1!</translation>
</message>
<message>
<location filename="../libs/main/application/pisystemmonitor.cpp" line="118"/>
<source>Can`t open process with ID = %1, %2!</source>
<translation>Невозможно открыть процесс с ID = %1, %2!</translation>
</message>
</context>
</TS>

1
lang/update.bat Normal file
View File

@@ -0,0 +1 @@
pip_tr --Parse -r -l ru -o pip_ru.ts ../libs

View File

@@ -0,0 +1,53 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_client.h"
#include "piclientserver_server.h"
#include "piethernet.h"
void PIClientServer::ServerClient::createForServer(Server * parent, PIEthernet * tcp_) {
tcp = tcp_;
tcp->setParameter(PIEthernet::KeepConnection, false);
init();
CONNECTL(tcp, disconnected, ([this, parent](bool) { parent->clientDisconnected(this); }));
}
PIClientServer::Client::Client() {
tcp = new PIEthernet(PIEthernet::TCP_Client);
tcp->setParameter(PIEthernet::KeepConnection, true);
own_tcp = true;
init();
}
PIClientServer::Client::~Client() {
if (tcp) tcp->setDebug(false);
close();
stopAndWait();
}
void PIClientServer::Client::connect(PINetworkAddress addr) {
if (!tcp || !own_tcp) return;
close();
tcp->connect(addr, true);
tcp->startThreadedRead();
}

View File

@@ -0,0 +1,117 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_client_base.h"
#include "piethernet.h"
#include "piliterals_time.h"
PIClientServer::ClientBase::ClientBase() {}
PIClientServer::ClientBase::~ClientBase() {
close();
stopAndWait();
if (own_tcp) piDeleteSafety(tcp);
piDeleteSafety(diag);
}
void PIClientServer::ClientBase::close() {
if (!tcp) return;
can_write = false;
tcp->stop();
stream.clear();
}
void PIClientServer::ClientBase::stopAndWait() {
if (!tcp) return;
tcp->stopAndWait(10_s);
if (tcp->isThreadedRead()) tcp->terminateThreadedRead();
tcp->close();
stream.clear();
}
int PIClientServer::ClientBase::write(const void * d, const size_t s) {
if (!tcp) return -1;
if (!can_write) return 0;
PIMutexLocker guard(write_mutex);
// piCout << "... send ...";
stream.send(PIByteArray(d, s));
// piCout << "... send ok";
return s;
}
void PIClientServer::ClientBase::enableDiagnostics() {
if (diag) return;
diag = new PIDiagnostics();
}
PIDiagnostics::State PIClientServer::ClientBase::diagnostics() const {
if (!diag) return {};
return diag->state();
}
int PIClientServer::ClientBase::receivePacketProgress() const {
return stream.receivePacketProgress();
}
void PIClientServer::ClientBase::init() {
if (!tcp) return;
CONNECTL(&stream, sendRequest, [this](const PIByteArray & ba) {
if (!can_write) return;
tcp->send(ba);
if (diag) diag->sended(ba.size_s());
// piMSleep(1);
});
CONNECTL(&stream, packetReceiveEvent, [this](PIByteArray & ba) { readed(ba); });
CONNECTL(&stream, startPacketReceive, [this](int size) { receivePacketStart(size); });
CONNECTL(&stream, endPacketReceive, [this]() { receivePacketEnd(); });
CONNECTL(tcp, threadedReadEvent, [this](const uchar * readed, ssize_t size) {
if (!can_write) return;
stream.received(readed, size);
if (diag) diag->received(size);
});
CONNECTL(tcp, connected, [this]() {
can_write = true;
// piCout << "Connected";
connected();
});
CONNECTL(tcp, disconnected, [this](bool) {
can_write = false;
stream.clear();
// piCout << "Disconnected";
disconnected();
});
}
void PIClientServer::ClientBase::destroy() {
write_mutex.lock();
close();
piDeleteSafety(tcp);
write_mutex.unlock();
// piCout << "Destroyed";
}

View File

@@ -0,0 +1,143 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_server.h"
#include "piclientserver_client.h"
#include "piethernet.h"
#include "pitranslator.h"
PIClientServer::Server::Server() {
tcp_server = new PIEthernet(PIEthernet::TCP_Server);
clean_thread = new PIThread();
client_factory = [] { return new ServerClient(); };
CONNECTL(tcp_server, newConnection, [this](PIEthernet * c) {
PIMutexLocker guard(clients_mutex);
if (clients.size_s() >= max_clients) {
piCout << "Server::newConnection overflow clients count"_tr("PIClientServer");
delete c;
return;
}
auto sc = client_factory();
if (!sc) {
piCout << "ClientFactory returns nullptr!"_tr("PIClientServer");
return;
}
sc->createForServer(this, c);
newClient(sc);
});
clean_thread->start([this]() {
clean_notifier.wait();
PIVector<ServerClient *> to_delete;
clients_mutex.lock();
for (auto c: clients) {
const PIEthernet * eth = c->getTCP();
if (!eth) continue;
if (eth->isConnected()) continue;
c->can_write = false;
to_delete << c;
}
for (auto c: to_delete)
clients.removeOne(c);
clients_mutex.unlock();
for (auto c: to_delete) {
c->aboutDelete();
c->destroy();
delete c;
}
});
}
PIClientServer::Server::~Server() {
clean_thread->stop();
clean_notifier.notify();
clean_thread->waitForFinish();
piDeleteSafety(clean_thread);
stopServer();
for (auto c: clients) {
c->aboutDelete();
c->destroy();
delete c;
}
piDeleteSafety(tcp_server);
}
void PIClientServer::Server::listen(PINetworkAddress addr) {
if (!tcp_server) return;
stopServer();
is_closing = false;
tcp_server->listen(addr, true);
// piCout << "Listen on" << addr.toString();
}
void PIClientServer::Server::closeAll() {
clients_mutex.lock();
for (auto c: clients) {
c->aboutDelete();
c->destroy();
delete c;
}
clients.clear();
clients_mutex.unlock();
}
void PIClientServer::Server::setMaxClients(int new_max_clients) {
max_clients = new_max_clients;
}
int PIClientServer::Server::clientsCount() const {
PIMutexLocker guard(clients_mutex);
return clients.size_s();
}
void PIClientServer::Server::forEachClient(std::function<void(ServerClient *)> func) {
PIMutexLocker guard(clients_mutex);
for (auto * c: clients) {
func(c);
if (is_closing) break;
}
}
void PIClientServer::Server::stopServer() {
if (!tcp_server) return;
is_closing = true;
tcp_server->stopThreadedListen();
tcp_server->stopAndWait();
}
void PIClientServer::Server::newClient(ServerClient * c) {
clients << c;
c->setConfiguration(configuration());
c->tcp->startThreadedRead();
c->connected();
}
void PIClientServer::Server::clientDisconnected(ServerClient * c) {
clean_notifier.notify();
}

View File

@@ -18,43 +18,43 @@
*/ */
#include "picloudclient.h" #include "picloudclient.h"
#include "picloudtcp.h" #include "picloudtcp.h"
#include "pitranslator.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() { PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
tcp.setRole(PICloud::TCP::Client); tcp.setRole(PICloud::TCP::Client);
setThreadedReadBufferSize(eth.threadedReadBufferSize());
setName("cloud_client"); setName("cloud_client");
is_connected = false; is_connected = false;
is_deleted = false; is_deleted = false;
// setReopenEnabled(false); // setReopenEnabled(false);
CONNECTL(&eth, connected, [this](){opened_ = true; tcp.sendStart();}); CONNECTL(&eth, connected, [this]() {
opened_ = true;
tcp.sendStart();
});
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, disconnected, [this](bool) { CONNECTL(&eth, disconnected, [this](bool) {
if (is_deleted) return; if (is_deleted) return;
bool need_disconn = is_connected; bool need_disconn = is_connected;
// piCoutObj << "eth disconnected"; // piCoutObj << "eth disconnected";
static_cast<PIThread*>(&eth)->stop(); eth.stop();
opened_ = false; opened_ = false;
internalDisconnect(); internalDisconnect();
if (need_disconn) if (need_disconn) disconnected();
disconnected();
// piCoutObj << "eth disconnected done"; // piCoutObj << "eth disconnected done";
}); });
} }
PICloudClient::~PICloudClient() { PICloudClient::~PICloudClient() {
//piCoutObj << "~PICloudClient()"; // piCoutObj << "~PICloudClient() ..." << this;
PIThread::stop();
//eth.close();
//if (is_connected) disconnected();
close();
//piCoutObj << "~PICloudClient() closed";
internalDisconnect();
// stop(false);
is_deleted = true; is_deleted = true;
stopAndWait();
close();
internalDisconnect(); internalDisconnect();
//piCoutObj << "~PICloudClient() done"; // piCoutObj << "~PICloudClient() done" << this;
} }
@@ -69,19 +69,26 @@ void PICloudClient::setKeepConnection(bool on) {
} }
void PICloudClient::interrupt() {
cond_buff.notifyOne();
cond_connect.notifyOne();
eth.interrupt();
}
bool PICloudClient::openDevice() { bool PICloudClient::openDevice() {
// piCoutObj << "open";// << path(); // piCoutObj << "open";// << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false); bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) { if (op) {
mutex_connect.lock(); mutex_connect.lock();
eth.startThreadedRead(); eth.startThreadedRead();
// piCoutObj << "connecting..."; // piCoutObj << "connecting...";
bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout()); bool conn_ok = cond_connect.waitFor(mutex_connect, eth.readTimeout());
// piCoutObj << "conn_ok" << conn_ok << is_connected; // piCoutObj << "conn_ok" << conn_ok << is_connected;
mutex_connect.unlock(); mutex_connect.unlock();
if (!conn_ok) { if (!conn_ok) {
mutex_connect.lock(); mutex_connect.lock();
eth.stop(); eth.stopAndWait();
eth.close(); eth.close();
mutex_connect.unlock(); mutex_connect.unlock();
} }
@@ -98,24 +105,28 @@ bool PICloudClient::closeDevice() {
if (is_connected) { if (is_connected) {
internalDisconnect(); internalDisconnect();
} }
eth.stop(); eth.stopAndWait();
eth.close(); eth.close();
return true; return true;
} }
ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) { ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) {
if (is_deleted) return -1; if (is_deleted || max_size <= 0) return -1;
//piCoutObj << "readDevice"; // piCoutObj << "readDevice ...";
if (!is_connected && eth.isClosed()) openDevice(); if (!is_connected && eth.isClosed()) openDevice();
ssize_t sz = -1; ssize_t sz = -1;
mutex_buff.lock(); mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
if (is_connected) { if (is_connected) {
sz = piMini(max_size, buff.size()); if (buff.isEmpty()) {
sz = 0;
} else {
sz = piMin<ssize_t>(max_size, buff.size_s());
memcpy(read_to, buff.data(), sz); memcpy(read_to, buff.data(), sz);
buff.remove(0, sz); buff.remove(0, sz);
} }
if (sz == 0) cond_buff.wait(mutex_buff);
}
mutex_buff.unlock(); mutex_buff.unlock();
if (!is_connected) opened_ = false; if (!is_connected) opened_ = false;
// piCoutObj << "readDevice done" << sz; // piCoutObj << "readDevice done" << sz;
@@ -124,13 +135,14 @@ ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) {
ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) { ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) {
if (is_deleted) return -1; if (is_deleted || !is_connected) return -1;
// piCoutObj << "writeDevice"; // piCoutObj << "writeDevice" << size;
return tcp.sendData(PIByteArray(data, size)); return tcp.sendData(PIByteArray(data, size));
} }
void PICloudClient::internalDisconnect() { void PICloudClient::internalDisconnect() {
// piCoutObj << "internalDisconnect";
is_connected = false; is_connected = false;
cond_buff.notifyOne(); cond_buff.notifyOne();
cond_connect.notifyOne(); cond_connect.notifyOne();
@@ -155,24 +167,26 @@ void PICloudClient::_readed(PIByteArray & ba) {
} }
break; break;
case PICloud::TCP::Disconnect: case PICloud::TCP::Disconnect:
static_cast<PIThread*>(&eth)->stop(); eth.stop();
opened_ = false; opened_ = false;
eth.close(); eth.close();
break; break;
case PICloud::TCP::Data: case PICloud::TCP::Data:
if (is_connected) { if (is_connected) {
mutex_buff.lock(); mutex_buff.lock();
if (buff.size_s() > threadedReadBufferSize()) {
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
mutex_buff.unlock();
return;
}
buff.append(ba); buff.append(ba);
mutex_buff.unlock(); mutex_buff.unlock();
cond_buff.notifyOne(); cond_buff.notifyOne();
} }
break; break;
default: default: break;
break;
} }
// piCoutObj << "readed" << ba.toHex(); // piCoutObj << "readed" << ba.toHex();
} }
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
// piCoutObj << "_readed done"; // piCoutObj << "_readed done";
} }

View File

@@ -19,30 +19,63 @@
#include "picloudserver.h" #include "picloudserver.h"
#include "piliterals_time.h"
#include "pitranslator.h"
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() { PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000); PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000);
tcp.setRole(PICloud::TCP::Server); tcp.setRole(PICloud::TCP::Server);
tcp.setServerName(server_name); tcp.setServerName(server_name);
setName("cloud_server__" + server_name); setName("cloud_server__" + server_name);
is_deleted = false;
eth.setReopenEnabled(false);
setThreadedReadBufferSize(eth.threadedReadBufferSize());
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed); CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();}); CONNECTL(&eth, connected, [this]() {
CONNECTL(&eth, disconnected, [this](bool){ open_mutex.lock();
piCoutObj << "disconnected"; opened_ = true;
static_cast<PIThread*>(&eth)->stop(); cvar.notifyOne();
opened_ = false; open_mutex.unlock();
ping_timer.stop(false); piCoutObj << "connected";
piMSleep(100); tcp.sendStart();
}); });
CONNECTL(&ping_timer, tickEvent, [this] (void *, int){ CONNECTL(&eth, disconnected, [this](bool) {
if (is_deleted) return;
piCoutObj << "disconnected";
clients_mutex.lock();
for (auto c: clients_) {
c->is_connected = false;
c->close();
}
removed_clients_.append(clients_);
clients_.clear();
index_clients.clear();
clients_mutex.unlock();
open_mutex.lock();
opened_ = false;
cvar.notifyOne();
open_mutex.unlock();
ping_timer.stop();
});
ping_timer.setSlot([this]() {
if (eth.isConnected()) tcp.sendPing(); if (eth.isConnected()) tcp.sendPing();
}); });
} }
PICloudServer::~PICloudServer() { PICloudServer::~PICloudServer() {
// piCoutObj << "~PICloudServer ..." << this;
is_deleted = true;
stop(); stop();
close(); close();
waitThreadedReadFinished();
// piCout << "wait";
while (removed_clients_.isNotEmpty()) {
Client * c = removed_clients_.take_back();
delete c;
}
// piCoutObj << "~PICloudServer done" << this;
} }
@@ -59,39 +92,48 @@ PIVector<PICloudServer::Client *> PICloudServer::clients() const {
bool PICloudServer::openDevice() { bool PICloudServer::openDevice() {
//piCout << "PICloudServer open device" << path(); piCoutObj << "open device" << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false); if (is_deleted) return false;
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) { if (op) {
eth.startThreadedRead(); eth.startThreadedRead();
ping_timer.start(5000); ping_timer.start(5_s);
return true; return true;
} } else {
ping_timer.stop(false); ping_timer.stop();
eth.close(); eth.close();
return false; return false;
} }
}
bool PICloudServer::closeDevice() { bool PICloudServer::closeDevice() {
eth.stop(); // piCoutObj << "closeDevice" << this;
ping_timer.stop(false); eth.stopAndWait();
ping_timer.stop();
eth.close();
cvar.notifyOne();
clients_mutex.lock(); clients_mutex.lock();
for (auto c: clients_) { for (auto c: clients_) {
c->is_connected = false;
c->close(); c->close();
c->stop();
} }
removed_clients_.append(clients_);
clients_.clear();
index_clients.clear();
clients_mutex.unlock(); clients_mutex.unlock();
eth.close();
for (auto c : clients_)
delete c;
return true; return true;
} }
ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) { ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) {
if (is_deleted) return -1;
// piCoutObj << "readDevice"; // piCoutObj << "readDevice";
if (!opened_) openDevice(); open_mutex.lock();
else piMSleep(eth.readTimeout()); if (isOpened()) cvar.wait(open_mutex);
open_mutex.unlock();
// piCoutObj << "opened_ = " << opened_;
// else piMSleep(eth.readTimeout());
return -1; return -1;
} }
@@ -102,12 +144,19 @@ ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) {
} }
void PICloudServer::interrupt() {
eth.interrupt();
cvar.notifyOne();
}
void PICloudServer::clientDisconnect(uint client_id) { void PICloudServer::clientDisconnect(uint client_id) {
tcp.sendDisconnected(client_id); tcp.sendDisconnected(client_id);
} }
int PICloudServer::sendData(const PIByteArray & data, uint client_id) { int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
if (!opened_) return -1;
return tcp.sendData(data, client_id); return tcp.sendData(data, client_id);
} }
@@ -115,17 +164,16 @@ int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client_id(id) { PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client_id(id) {
setMode(PIIODevice::ReadWrite); setMode(PIIODevice::ReadWrite);
setReopenEnabled(false); setReopenEnabled(false);
setThreadedReadBufferSize(server->threadedReadBufferSize());
is_connected = true; is_connected = true;
} }
PICloudServer::Client::~Client() { PICloudServer::Client::~Client() {
if (is_connected) { // piCoutObj << "~PICloudServer::Client..." << this;
is_connected = false;
cond_buff.notifyOne();
}
close(); close();
stop(); stopAndWait(10_s);
// piCoutObj << "~PICloudServer::Client done" << this;
} }
@@ -135,7 +183,7 @@ bool PICloudServer::Client::openDevice() {
bool PICloudServer::Client::closeDevice() { bool PICloudServer::Client::closeDevice() {
PIThread::stop(false); // piCoutObj << "closeDevice" << this;
if (is_connected) { if (is_connected) {
server->clientDisconnect(client_id); server->clientDisconnect(client_id);
is_connected = false; is_connected = false;
@@ -149,33 +197,48 @@ ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) {
if (!is_connected) return -1; if (!is_connected) return -1;
ssize_t sz = -1; ssize_t sz = -1;
mutex_buff.lock(); mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty() || !is_connected;});
if (is_connected) { if (is_connected) {
if (buff.isEmpty()) {
sz = 0;
} else {
sz = piMini(max_size, buff.size()); sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz); memcpy(read_to, buff.data(), sz);
buff.remove(0, sz); buff.remove(0, sz);
} }
if (sz == 0) cond_buff.wait(mutex_buff);
}
mutex_buff.unlock(); mutex_buff.unlock();
return sz; return sz;
} }
ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) { ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) {
if (!is_connected) return -1;
return server->sendData(PIByteArray(data, size), client_id); return server->sendData(PIByteArray(data, size), client_id);
} }
void PICloudServer::Client::interrupt() {
cond_buff.notifyOne();
}
void PICloudServer::Client::pushBuffer(const PIByteArray & ba) { void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
if (!is_connected) return; if (!is_connected) return;
mutex_buff.lock(); mutex_buff.lock();
if (buff.size_s() > threadedReadBufferSize()) {
piCoutObj << "Error: buffer overflow, drop %1 bytes"_tr("PICloud").arg(ba.size());
mutex_buff.unlock();
return;
}
buff.append(ba); buff.append(ba);
cond_buff.notifyOne(); cond_buff.notifyOne();
mutex_buff.unlock(); mutex_buff.unlock();
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100); // FIXME: sleep here is bad
} }
void PICloudServer::_readed(PIByteArray & ba) { void PICloudServer::_readed(PIByteArray & ba) {
if (is_deleted) return;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba); PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
if (hdr.second == tcp.role()) { if (hdr.second == tcp.role()) {
switch (hdr.first) { switch (hdr.first) {
@@ -185,10 +248,11 @@ void PICloudServer::_readed(PIByteArray & ba) {
Client * oc = index_clients.value(id, nullptr); Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock(); clients_mutex.unlock();
if (oc) { if (oc) {
piCoutObj << "Warning: reject client with duplicated ID"_tr("PICloud");
tcp.sendDisconnected(id); tcp.sendDisconnected(id);
} else { } else {
//piCoutObj << "new Client" << id;
Client * c = new Client(this, id); Client * c = new Client(this, id);
// piCoutObj << "new Client" << id << c;
CONNECT1(void, PIObject *, c, deleted, this, clientDeleted); CONNECT1(void, PIObject *, c, deleted, this, clientDeleted);
clients_mutex.lock(); clients_mutex.lock();
clients_ << c; clients_ << c;
@@ -199,13 +263,17 @@ void PICloudServer::_readed(PIByteArray & ba) {
} break; } break;
case PICloud::TCP::Disconnect: { case PICloud::TCP::Disconnect: {
uint id = tcp.parseDisconnect(ba); uint id = tcp.parseDisconnect(ba);
//piCoutObj << "remove Client" << id; // piCoutObj << "Close on logic";
clients_mutex.lock(); clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr); Client * oc = index_clients.take(id, nullptr);
clients_.removeOne(oc);
clients_mutex.unlock(); clients_mutex.unlock();
if (oc) { if (oc) {
oc->stopAndWait();
oc->is_connected = false; oc->is_connected = false;
oc->close(); oc->close();
removed_clients_ << oc;
// delete oc;
} }
} break; } break;
case PICloud::TCP::Data: { case PICloud::TCP::Data: {
@@ -213,7 +281,7 @@ void PICloudServer::_readed(PIByteArray & ba) {
clients_mutex.lock(); clients_mutex.lock();
Client * oc = index_clients.value(d.first, nullptr); Client * oc = index_clients.value(d.first, nullptr);
clients_mutex.unlock(); clients_mutex.unlock();
//piCoutObj << "data for" << d.first << d.second.toHex(); // piCoutObj << "data for" << d.first << d.second.size();
if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second); if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} break; } break;
default: break; default: break;
@@ -224,15 +292,10 @@ void PICloudServer::_readed(PIByteArray & ba) {
void PICloudServer::clientDeleted(PIObject * o) { void PICloudServer::clientDeleted(PIObject * o) {
PICloudServer::Client * c = (PICloudServer::Client *)o; PICloudServer::Client * c = (PICloudServer::Client *)o;
// piCoutObj << "clientDeleted" << c;
clients_mutex.lock(); clients_mutex.lock();
clients_.removeOne(c); clients_.removeOne(c);
auto it = index_clients.makeIterator(); removed_clients_.removeAll(c);
while (it.hasNext()) { index_clients.removeWhere([c](uint, Client * v) { return v == c; });
it.next();
if (it.value() == c) {
index_clients.remove(it.key());
break;
}
}
clients_mutex.unlock(); clients_mutex.unlock();
} }

View File

@@ -18,10 +18,12 @@
*/ */
#include "picloudtcp.h" #include "picloudtcp.h"
#include "picrypt.h"
#include "pichunkstream.h" #include "pichunkstream.h"
#include "picrypt.h"
#include "piethernet.h" #include "piethernet.h"
#include "pistreampacker.h" #include "pistreampacker.h"
#include "pitranslator.h"
const char hash_cloud_key[] = "_picloud_"; const char hash_cloud_key[] = "_picloud_";
@@ -43,7 +45,8 @@ void PICloud::TCP::setRole(PICloud::TCP::Role r) {
void PICloud::TCP::setServerName(const PIString & server_name_) { void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_; server_name = server_name_;
suuid = PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key)); suuid =
PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
} }
@@ -132,7 +135,8 @@ PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteA
PICloud::TCP::Header hdr; PICloud::TCP::Header hdr;
ba >> hdr; ba >> hdr;
if (hdr.version != header.version) { if (hdr.version != header.version) {
piCout << "[PICloud]" << "invalid PICloud::TCP version!"; piCout << "[PICloud]"
<< "Invalid PICloud::TCP version!"_tr("PICloud");
return ret; return ret;
} }
ret.first = (Type)hdr.type; ret.first = (Type)hdr.type;

View File

@@ -18,6 +18,8 @@
*/ */
#include "picompress.h" #include "picompress.h"
#include "pitranslator.h"
#ifdef PIP_COMPRESS #ifdef PIP_COMPRESS
# ifdef ESP_PLATFORM # ifdef ESP_PLATFORM
# include "esp32/rom/miniz.h" # include "esp32/rom/miniz.h"
@@ -38,14 +40,16 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
ulong sz = zba.size(); ulong sz = zba.size();
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level); ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
if (ret != Z_OK) { if (ret != Z_OK) {
piCout << "[PICompress]" << "Error: invalid input or not enought memory"; piCout << "[PICompress]"
<< "Error: invalid input or not enought memory"_tr("PICompress");
return ba; return ba;
} }
zba.resize(sz); zba.resize(sz);
zba << ullong(ba.size()); zba << ullong(ba.size());
return zba; return zba;
#else #else
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"; piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif #endif
return ba; return ba;
} }
@@ -55,7 +59,8 @@ PIByteArray piDecompress(const PIByteArray & zba) {
#ifdef PIP_COMPRESS #ifdef PIP_COMPRESS
ullong sz = 0; ullong sz = 0;
if (zba.size() < sizeof(ullong)) { if (zba.size() < sizeof(ullong)) {
piCout << "[PICompress]" << "Error: invalid input"; piCout << "[PICompress]"
<< "Error: invalid input"_tr("PICompress");
return zba; return zba;
} }
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong)); PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
@@ -65,12 +70,14 @@ PIByteArray piDecompress(const PIByteArray & zba) {
ulong s = sz; ulong s = sz;
ret = uncompress(ba.data(), &s, zba.data(), zba.size()); ret = uncompress(ba.data(), &s, zba.data(), zba.size());
if (ret != Z_OK) { if (ret != Z_OK) {
piCout << "[PICompress]" << "Error: invalid input or not enought memory"; piCout << "[PICompress]"
<< "Error: invalid input or not enought memory"_tr("PICompress");
return zba; return zba;
} }
return ba; return ba;
#else #else
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"; piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library"_tr("PICompress");
#endif #endif
return zba; return zba;
} }

View File

@@ -17,10 +17,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piscreen.h" #include "piscreen.h"
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piliterals_time.h"
// clang-format off
#ifndef WINDOWS #ifndef WINDOWS
# include <sys/ioctl.h>
# include <fcntl.h> # include <fcntl.h>
# include <sys/ioctl.h>
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h> # include <wingdi.h>
@@ -29,6 +32,7 @@
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
# endif # endif
#endif #endif
// clang-format on
using namespace PIScreenTypes; using namespace PIScreenTypes;
@@ -244,10 +248,14 @@ void PIScreen::SystemConsole::print() {
# define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) # define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr; WORD attr = PRIVATE->dattr;
if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY; if (c.format.flags & Bold)
else attr &= ~FOREGROUND_INTENSITY; attr |= FOREGROUND_INTENSITY;
if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE; else
else attr &= ~COMMON_LVB_UNDERSCORE; attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline)
attr |= COMMON_LVB_UNDERSCORE;
else
attr &= ~COMMON_LVB_UNDERSCORE;
switch (c.format.color_char) { switch (c.format.color_char) {
case Black: attr = (attr & ~FOREGROUND_MASK); break; case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break; case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
@@ -292,7 +300,8 @@ void PIScreen::SystemConsole::clearLine() {
void PIScreen::SystemConsole::newLine() { void PIScreen::SystemConsole::newLine() {
getWinCurCoord(); getWinCurCoord();
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++; PRIVATE->ccoord.X = 0;
PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord); SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
} }
#else // WINDOWS #else // WINDOWS
@@ -358,8 +367,16 @@ void PIScreen::SystemConsole::clearScreen() {
void PIScreen::SystemConsole::clearScreenLower() { void PIScreen::SystemConsole::clearScreenLower() {
#ifdef WINDOWS #ifdef WINDOWS
getWinCurCoord(); getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); FillConsoleOutputAttribute(PRIVATE->hOut,
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written); PRIVATE->dattr,
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut,
' ',
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
#else #else
printf("\e[0m\e[J"); printf("\e[0m\e[J");
#endif #endif
@@ -384,7 +401,7 @@ void PIScreen::SystemConsole::showCursor() {
} }
// PIScreen
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") { PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen"); setName("screen");
@@ -403,8 +420,8 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe
PIScreen::~PIScreen() { PIScreen::~PIScreen() {
if (isRunning()) stop(); if (isRunning()) stop();
PIThread::waitForFinish(10); PIThread::waitForFinish(100_ms);
listener->waitForFinish(10); listener->waitForFinish(100_ms);
delete listener; delete listener;
} }
@@ -422,14 +439,12 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
return; return;
*/ */
PIScreenTile * rtile = rootTile(); PIScreenTile * rtile = rootTile();
if (tile_dialog) if (tile_dialog) rtile = tile_dialog;
rtile = tile_dialog;
bool used = nextFocus(rtile, key); bool used = nextFocus(rtile, key);
if (used) return; if (used) return;
if (!used && tile_focus) { if (!used && tile_focus) {
if (tile_focus->visible) { if (tile_focus->visible) {
if (tile_focus->keyEvent(key)) if (tile_focus->keyEvent(key)) return;
return;
} }
} }
if (ret_func != 0) ret_func(key, data_); if (ret_func != 0) ret_func(key, data_);
@@ -455,7 +470,6 @@ PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e)
ff = true; ff = true;
} }
} }
} }
return tl; return tl;
} }
@@ -488,15 +502,13 @@ void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
if (tl.isEmpty()) return; if (tl.isEmpty()) return;
piForeachR(PIScreenTile * t, tl) piForeachR(PIScreenTile * t, tl)
if (t->wheelEvent(we)) break; if (t->wheelEvent(we)) break;
} }
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) { bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile *> vtl = rt->children(true), ftl; PIVector<PIScreenTile *> vtl = rt->children(true), ftl;
piForeach (PIScreenTile * t, vtl) { for (PIScreenTile * t: vtl) {
if (t->focus_flags[CanHasFocus]) if (t->focus_flags[CanHasFocus]) ftl << t;
ftl << t;
} }
int ind = -1; int ind = -1;
for (int i = 0; i < ftl.size_s(); ++i) for (int i = 0; i < ftl.size_s(); ++i)
@@ -504,18 +516,15 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
ind = i; ind = i;
break; break;
} }
if (ind < 0) if (ind < 0) tile_focus = 0;
tile_focus = 0;
if (ftl.isEmpty()) if (ftl.isEmpty())
tile_focus = 0; tile_focus = 0;
else { else {
if (tile_focus) if (tile_focus)
if (!tile_focus->visible) if (!tile_focus->visible) tile_focus = 0;
tile_focus = 0;
int next = tile_focus ? 0 : 1; int next = tile_focus ? 0 : 1;
if (tile_focus) { if (tile_focus) {
if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) next = 1;
next = 1;
if (tile_focus->focus_flags[NextByArrowsHorizontal]) { if (tile_focus->focus_flags[NextByArrowsHorizontal]) {
if (key.key == PIKbdListener::LeftArrow) next = -1; if (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1; if (key.key == PIKbdListener::RightArrow) next = 1;
@@ -528,7 +537,7 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
// piCout << ftl.size() << ind << next; // piCout << ftl.size() << ind << next;
if (next != 0) { if (next != 0) {
PIVector<PIScreenTile *> tl = rt->children(); PIVector<PIScreenTile *> tl = rt->children();
piForeach (PIScreenTile * t, tl) for (PIScreenTile * t: tl)
t->has_focus = false; t->has_focus = false;
if (!ftl.isEmpty()) { if (!ftl.isEmpty()) {
ind += next; ind += next;
@@ -550,22 +559,19 @@ void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
void PIScreen::tileRemovedInternal(PIScreenTile * t) { void PIScreen::tileRemovedInternal(PIScreenTile * t) {
if (tile_dialog == t) if (tile_dialog == t) tile_dialog = 0;
tile_dialog = 0;
} }
void PIScreen::tileSetFocusInternal(PIScreenTile * t) { void PIScreen::tileSetFocusInternal(PIScreenTile * t) {
PIScreenTile * rt = rootTile(); PIScreenTile * rt = rootTile();
if (tile_dialog) if (tile_dialog) rt = tile_dialog;
rt = tile_dialog;
PIVector<PIScreenTile *> tl = rt->children(), ftl; PIVector<PIScreenTile *> tl = rt->children(), ftl;
piForeach (PIScreenTile * i, tl) for (PIScreenTile * i: tl)
i->has_focus = false; i->has_focus = false;
tile_focus = t; tile_focus = t;
if (!tile_focus) return; if (!tile_focus) return;
if (tile_focus->focus_flags[CanHasFocus]) if (tile_focus->focus_flags[CanHasFocus]) tile_focus->has_focus = true;
tile_focus->has_focus = true;
} }
@@ -587,8 +593,14 @@ void PIScreen::waitForFinish() {
} }
void PIScreen::start(bool wait) {
PIThread::start(25_Hz);
if (wait) waitForFinish();
}
void PIScreen::stop(bool clear) { void PIScreen::stop(bool clear) {
PIThread::stop(true); PIThread::stopAndWait();
if (clear) console.clearScreen(); if (clear) console.clearScreen();
#ifndef WINDOWS #ifndef WINDOWS
fflush(0); fflush(0);
@@ -620,8 +632,13 @@ void PIScreen::run() {
tile_dialog->height_ = sh; tile_dialog->height_ = sh;
tile_dialog->layout(); tile_dialog->layout();
int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_; int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_;
drawer_.drawFrame(dx, dy, dx + dw + 1, dy + dh + 1, (Color)tile_dialog->back_format.color_char, drawer_.drawFrame(dx,
(Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags); dy,
dx + dw + 1,
dy + dh + 1,
(Color)tile_dialog->back_format.color_char,
(Color)tile_dialog->back_format.color_back,
(CharFlags)tile_dialog->back_format.flags);
tile_dialog->drawEventInternal(&drawer_); tile_dialog->drawEventInternal(&drawer_);
} }
console.print(); console.print();
@@ -636,9 +653,7 @@ void PIScreen::end() {
PIScreenTile * PIScreen::tileByName(const PIString & name) { PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile *> tl(tiles()); PIVector<PIScreenTile *> tl(tiles());
piForeach (PIScreenTile * t, tl) for (PIScreenTile * t: tl)
if (t->name() == name) if (t->name() == name) return t;
return t;
return 0; return 0;
} }

View File

@@ -27,16 +27,9 @@ TileVars::TileVars(const PIString &n) : PIScreenTile(n) {
} }
void TileVars::sizeHint(int &w, int &h) const { void TileVars::sizeHint(int & w, int & h) const {}
} void TileVars::drawEvent(PIScreenDrawer * d) {}
void TileVars::drawEvent(PIScreenDrawer *d) {
}
PIScreenConsoleTile::PIScreenConsoleTile() { PIScreenConsoleTile::PIScreenConsoleTile() {}
}

View File

@@ -117,26 +117,24 @@ void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c,
float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0; float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0;
int dx = x0 < x1 ? 1 : -1; int dx = x0 < x1 ? 1 : -1;
for (int i = x0; i != x1; i += dx) { for (int i = x0; i != x1; i += dx) {
x = i; y = piRound(cy); x = i;
if (x >= 0 && x < width && y >= 0 && y < height) y = piRound(cy);
cells[y][x] = cc; if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc;
cy += dy; cy += dy;
} }
y = piRound(cy); y = piRound(cy);
if (x1 >= 0 && x1 < width && y >= 0 && y < height) if (x1 >= 0 && x1 < width && y >= 0 && y < height) cells[y][x1] = cc;
cells[y][x1] = cc;
} else { } else {
float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0; float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0;
int dy = y0 < y1 ? 1 : -1; int dy = y0 < y1 ? 1 : -1;
for (int i = y0; i != y1; i += dy) { for (int i = y0; i != y1; i += dy) {
x = piRound(cx); y = i; x = piRound(cx);
if (x >= 0 && x < width && y >= 0 && y < height) y = i;
cells[y][x] = cc; if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc;
cx += dx; cx += dx;
} }
x = piRound(cx); x = piRound(cx);
if (x >= 0 && x < width && y1 >= 0 && y1 < height) if (x >= 0 && x < width && y1 >= 0 && y1 < height) cells[y1][x] = cc;
cells[y1][x] = cc;
} }
} }
@@ -157,19 +155,16 @@ void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c,
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width) if (i >= 0 && i < width) cv[i] = cc;
cv[i] = cc;
} }
j = xs[k]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
for (int i = y0; i != y1; i += dy) for (int i = y0; i != y1; i += dy)
if (i >= 0 && i < height) if (i >= 0 && i < height) cells[i][j] = cc;
cells[i][j] = cc;
} }
} }
int i = x1, j = y1; int i = x1, j = y1;
if (i >= 0 && i < width && j >= 0 && j < height) if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
cells[j][i] = cc;
} }
@@ -189,24 +184,26 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
cc.symbol = artChar(LineHorizontal); cc.symbol = artChar(LineHorizontal);
for (int i = x0 + 1; i != x1; i += dx) for (int i = x0 + 1; i != x1; i += dx)
if (i >= 0 && i < width) if (i >= 0 && i < width) cv[i] = cc;
cv[i] = cc;
} }
j = xs[k]; j = xs[k];
if (j >= 0 && j < width) { if (j >= 0 && j < width) {
cc.symbol = artChar(LineVertical); cc.symbol = artChar(LineVertical);
for (int i = y0 + 1; i != y1; i += dy) for (int i = y0 + 1; i != y1; i += dy)
if (i >= 0 && i < height) if (i >= 0 && i < height) cells[i][j] = cc;
cells[i][j] = cc;
} }
} }
int i = x0, j = y0; cc.symbol = artChar(CornerTopLeft); int i = x0, j = y0;
cc.symbol = artChar(CornerTopLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y0; cc.symbol = artChar(CornerTopRight); i = x1, j = y0;
cc.symbol = artChar(CornerTopRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x0, j = y1; cc.symbol = artChar(CornerBottomLeft); i = x0, j = y1;
cc.symbol = artChar(CornerBottomLeft);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
i = x1, j = y1; cc.symbol = artChar(CornerBottomRight); i = x1, j = y1;
cc.symbol = artChar(CornerBottomRight);
if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc; if (i >= 0 && i < width && j >= 0 && j < height) cells[j][i] = cc;
} }
@@ -224,8 +221,7 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c,
if (j >= 0 && j < height) { if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]); PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx) for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width) if (i >= 0 && i < width) cv[i] = cc;
cv[i] = cc;
} }
} }
@@ -241,8 +237,7 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<
PIVector<Cell> & cv(cells[y0 + j]); PIVector<Cell> & cv(cells[y0 + j]);
PIVector<Cell> & contv(content[j]); PIVector<Cell> & contv(content[j]);
for (int i = 0; i < piMini(w, contv.size_s()); ++i) for (int i = 0; i < piMini(w, contv.size_s()); ++i)
if ((i + x0) >= 0 && (i + x0) < width) if ((i + x0) >= 0 && (i + x0) < width) cv[x0 + i] = contv[i];
cv[x0 + i] = contv[i];
} }
} }
} }

View File

@@ -18,6 +18,7 @@
*/ */
#include "piscreentile.h" #include "piscreentile.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -41,8 +42,7 @@ PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObj
PIScreenTile::~PIScreenTile() { PIScreenTile::~PIScreenTile() {
// piCout << this << "~"; // piCout << this << "~";
if (screen) if (screen) screen->tileRemovedInternal(this);
screen->tileRemovedInternal(this);
setScreen(0); setScreen(0);
deleteChildren(); deleteChildren();
if (!parent) return; if (!parent) return;
@@ -78,18 +78,16 @@ void PIScreenTile::removeTile(PIScreenTile * t) {
PIVector<PIScreenTile *> PIScreenTile::children(bool only_visible) { PIVector<PIScreenTile *> PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile *> ret; PIVector<PIScreenTile *> ret;
piForeach (PIScreenTile * t, tiles) for (auto * t: tiles)
if (t->visible || !only_visible) if (t->visible || !only_visible) ret << t << t->children(only_visible);
ret << t << t->children(only_visible);
return ret; return ret;
} }
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) { PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
piForeach (PIScreenTile * t, tiles) { for (auto * t: tiles) {
if (!t->visible) continue; if (!t->visible) continue;
if (x >= t->x_ && (x - t->x_) < t->width_ && if (x >= t->x_ && (x - t->x_) < t->width_ && y >= t->y_ && (y - t->y_) < t->height_) {
y >= t->y_ && (y - t->y_) < t->height_) {
return t; return t;
} }
} }
@@ -105,13 +103,13 @@ void PIScreenTile::raiseEvent(TileEvent e) {
void PIScreenTile::setScreen(PIScreenBase * s) { void PIScreenTile::setScreen(PIScreenBase * s) {
screen = s; screen = s;
piForeach (PIScreenTile * t, tiles) for (auto * t: tiles)
t->setScreen(s); t->setScreen(s);
} }
void PIScreenTile::deleteChildren() { void PIScreenTile::deleteChildren() {
piForeach (PIScreenTile * t, tiles) { for (auto * t: tiles) {
t->parent = 0; t->parent = 0;
delete t; delete t;
} }
@@ -129,9 +127,16 @@ void PIScreenTile::drawEventInternal(PIScreenDrawer * d) {
if (!visible) { if (!visible) {
return; return;
} }
d->fillRect(x_, y_, x_ + width_, y_ + height_, back_symbol, (Color)back_format.color_char, (Color)back_format.color_back, back_format.flags); d->fillRect(x_,
y_,
x_ + width_,
y_ + height_,
back_symbol,
(Color)back_format.color_char,
(Color)back_format.color_back,
back_format.flags);
drawEvent(d); drawEvent(d);
piForeach (PIScreenTile * t, tiles) for (auto * t: tiles)
t->drawEventInternal(d); t->drawEventInternal(d);
} }
@@ -141,18 +146,22 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
h = 0; h = 0;
if (tiles.isEmpty()) return; if (tiles.isEmpty()) return;
int sl = spacing * (tiles.size_s() - 1); int sl = spacing * (tiles.size_s() - 1);
if (direction == Horizontal) w += sl; if (direction == Horizontal)
else h += sl; w += sl;
piForeachC (PIScreenTile * t, tiles) { else
h += sl;
for (const auto * t: tiles) {
if (!t->visible) continue; if (!t->visible) continue;
int cw(0), ch(0); int cw(0), ch(0);
t->sizeHint(cw, ch); t->sizeHint(cw, ch);
cw = piClampi(cw, t->minimumWidth, t->maximumWidth); cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
ch = piClampi(ch, t->minimumHeight, t->maximumHeight); ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
if (direction == Horizontal) { if (direction == Horizontal) {
w += cw; h = piMaxi(h, ch); w += cw;
h = piMaxi(h, ch);
} else { } else {
h += ch; w = piMaxi(w, cw); h += ch;
w = piMaxi(w, cw);
} }
} }
w += marginLeft + marginRight; w += marginLeft + marginRight;
@@ -210,8 +219,7 @@ void PIScreenTile::layout() {
for (int j = 0; j < tiles.size_s(); ++j) { for (int j = 0; j < tiles.size_s(); ++j) {
if (i == j) continue; if (i == j) continue;
if (max_tl[j]) continue; if (max_tl[j]) continue;
if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout()) if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout()) asizes[j] += pas;
asizes[j] += pas;
} }
} }
} }
@@ -241,8 +249,7 @@ void PIScreenTile::layout() {
t->height_ = hints[i]; t->height_ = hints[i];
cy += hints[i] + spacing; cy += hints[i] + spacing;
} }
if (t->pw != t->width_ || t->ph != t->height_) if (t->pw != t->width_ || t->ph != t->height_) t->resizeEvent(t->width_, t->height_);
t->resizeEvent(t->width_, t->height_);
t->pw = t->width_; t->pw = t->width_;
t->ph = t->height_; t->ph = t->height_;
t->layout(); t->layout();

View File

@@ -18,6 +18,7 @@
*/ */
#include "piscreentiles.h" #include "piscreentiles.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
@@ -37,7 +38,7 @@ TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() {
void TileSimple::sizeHint(int & w, int & h) const { void TileSimple::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
piForeachC (Row & r, content) for (const auto & r: content)
w = piMaxi(w, r.first.size_s()); w = piMaxi(w, r.first.size_s());
h = content.size_s(); h = content.size_s();
} }
@@ -57,7 +58,7 @@ void TileSimple::drawEvent(PIScreenDrawer * d) {
} }
// TileScrollBar
TileScrollBar::TileScrollBar(const PIString & n) { TileScrollBar::TileScrollBar(const PIString & n) {
direction = Vertical; direction = Vertical;
@@ -122,7 +123,7 @@ bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileList
TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) { TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
alignment = Left; alignment = Left;
@@ -138,7 +139,7 @@ TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
void TileList::sizeHint(int & w, int & h) const { void TileList::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
piForeachC (Row & r, content) for (const auto & r: content)
w = piMaxi(w, r.first.size_s()); w = piMaxi(w, r.first.size_s());
h = 3; h = 3;
} }
@@ -188,9 +189,7 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
lhei = height_ - 2; lhei = height_ - 2;
int oo(0), osp = piMini(3, lhei / 4); int oo(0), osp = piMini(3, lhei / 4);
switch (key.key) { switch (key.key) {
case PIKbdListener::PageUp: case PIKbdListener::PageUp: cur -= lhei / 2; oo -= lhei / 2;
cur -= lhei / 2;
oo -= lhei / 2;
case PIKbdListener::UpArrow: case PIKbdListener::UpArrow:
cur--; cur--;
oo--; oo--;
@@ -207,7 +206,8 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
switch (selection_mode) { switch (selection_mode) {
case NoSelection: return false; case NoSelection: return false;
case SingleSelection: case SingleSelection:
if (selected.isEmpty()) selected << cur; if (selected.isEmpty())
selected << cur;
else { else {
bool add = !selected[cur]; bool add = !selected[cur];
selected.clear(); selected.clear();
@@ -216,8 +216,10 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
return true; return true;
case MultiSelection: case MultiSelection:
if (selected[cur]) selected.remove(cur); if (selected[cur])
else selected << cur; selected.remove(cur);
else
selected << cur;
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
} }
@@ -238,17 +240,14 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei; if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
return true; return true;
case PIKbdListener::Home: case PIKbdListener::Home: cur = offset = 0; return true;
cur = offset = 0;
return true;
case PIKbdListener::End: case PIKbdListener::End:
cur = content.size_s() - 1; cur = content.size_s() - 1;
offset = content.size_s() - lhei; offset = content.size_s() - lhei;
if (offset < 0) offset = 0; if (offset < 0) offset = 0;
return true; return true;
case PIKbdListener::Return: case PIKbdListener::Return:
if (cur >= 0 && cur < content.size_s()) if (cur >= 0 && cur < content.size_s()) raiseEvent(TileEvent(RowPressed, cur));
raiseEvent(TileEvent(RowPressed, cur));
return true; return true;
case '*': case '*':
if (selection_mode == TileList::MultiSelection) { if (selection_mode == TileList::MultiSelection) {
@@ -278,12 +277,8 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
if (mp < 0 || mp >= content.size_s()) return true; if (mp < 0 || mp >= content.size_s()) return true;
cur = mp; cur = mp;
switch (me.action) { switch (me.action) {
case PIKbdListener::MouseButtonPress: case PIKbdListener::MouseButtonPress: mouse_sel = !selected.contains(cur); break;
mouse_sel = !selected.contains(cur); case PIKbdListener::MouseButtonDblClick: keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); return true;
break;
case PIKbdListener::MouseButtonDblClick:
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
return true;
default: break; default: break;
} }
if (me.buttons[PIKbdListener::MouseRight]) { if (me.buttons[PIKbdListener::MouseRight]) {
@@ -294,8 +289,10 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
case MultiSelection: case MultiSelection:
if (mouse_sel) selected << cur; if (mouse_sel)
else selected.remove(cur); selected << cur;
else
selected.remove(cur);
raiseEvent(TileEvent(SelectionChanged)); raiseEvent(TileEvent(SelectionChanged));
break; break;
default: break; default: break;
@@ -311,7 +308,7 @@ bool TileList::wheelEvent(PIKbdListener::WheelEvent we) {
} }
// TileButton
TileButton::TileButton(const PIString & n): PIScreenTile(n) { TileButton::TileButton(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
@@ -351,7 +348,7 @@ bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileButtons
TileButtons::TileButtons(const PIString & n): PIScreenTile(n) { TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
@@ -364,12 +361,12 @@ TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
void TileButtons::sizeHint(int & w, int & h) const { void TileButtons::sizeHint(int & w, int & h) const {
w = h = 0; w = h = 0;
if (direction == Horizontal) { if (direction == Horizontal) {
piForeachC (Button & b, content) for (const auto & b: content)
w += b.first.size_s() + 4; w += b.first.size_s() + 4;
w += piMaxi(0, content.size_s() - 1) * 2; w += piMaxi(0, content.size_s() - 1) * 2;
h += 1; h += 1;
} else { } else {
piForeachC (Button & b, content) for (const auto & b: content)
w = piMaxi(w, b.first.size_s() + 4); w = piMaxi(w, b.first.size_s() + 4);
h += content.size_s(); h += content.size_s();
h += piMaxi(0, content.size_s() - 1); h += piMaxi(0, content.size_s() - 1);
@@ -387,8 +384,7 @@ void TileButtons::drawEvent(PIScreenDrawer * d) {
case PIScreenTypes::Right: dx = width_ - shw; break; case PIScreenTypes::Right: dx = width_ - shw; break;
default: break; default: break;
} }
if (direction == PIScreenTypes::Horizontal) if (direction == PIScreenTypes::Horizontal) cx += dx;
cx += dx;
for (int i = 0; i < content.size_s(); ++i) { for (int i = 0; i < content.size_s(); ++i) {
Color cb = Cyan; Color cb = Cyan;
Color ct = Black; Color ct = Black;
@@ -430,9 +426,7 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
if (cur >= content.size_s()) cur = content.size_s() - 1; if (cur >= content.size_s()) cur = content.size_s() - 1;
return true; return true;
case PIKbdListener::Space: case PIKbdListener::Space:
case PIKbdListener::Return: case PIKbdListener::Return: raiseEvent(TileEvent(ButtonSelected, cur)); return true;
raiseEvent(TileEvent(ButtonSelected, cur));
return true;
}; };
return PIScreenTile::keyEvent(key); return PIScreenTile::keyEvent(key);
} }
@@ -441,8 +435,7 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) { bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) { if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) {
for (int i = 0; i < btn_rects.size_s(); ++i) for (int i = 0; i < btn_rects.size_s(); ++i)
if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 && if (me.x >= btn_rects[i].x0 && me.x < btn_rects[i].x1 && me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) {
me.y >= btn_rects[i].y0 && me.y < btn_rects[i].y1) {
cur = i; cur = i;
break; break;
} }
@@ -454,7 +447,7 @@ bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileCheck
TileCheck::TileCheck(const PIString & n): PIScreenTile(n) { TileCheck::TileCheck(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
@@ -499,7 +492,7 @@ bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) {
} }
// TileProgress
TileProgress::TileProgress(const PIString & n): PIScreenTile(n) { TileProgress::TileProgress(const PIString & n): PIScreenTile(n) {
maximum = 100.; maximum = 100.;
@@ -532,7 +525,7 @@ void TileProgress::drawEvent(PIScreenDrawer * d) {
} }
// TilePICout
TilePICout::TilePICout(const PIString & n): TileList(n) { TilePICout::TilePICout(const PIString & n): TileList(n) {
max_lines = 1024; max_lines = 1024;
@@ -546,10 +539,9 @@ void TilePICout::drawEvent(PIScreenDrawer * d) {
if (!out.isEmpty()) { if (!out.isEmpty()) {
PIStringList l = out.split("\n"); PIStringList l = out.split("\n");
bool scroll = (cur == content.size_s() - 1) || !has_focus; bool scroll = (cur == content.size_s() - 1) || !has_focus;
piForeachC (PIString & s, l) for (const auto & s: l)
content << TileList::Row(s.trimmed(), format); content << TileList::Row(s.trimmed(), format);
if (content.size_s() > max_lines) if (content.size_s() > max_lines) content.remove(0, content.size_s() - max_lines);
content.remove(0, content.size_s() - max_lines);
if (scroll) { if (scroll) {
offset = piMaxi(0, content.size_s() - lhei); offset = piMaxi(0, content.size_s() - lhei);
cur = content.size_s() - 1; cur = content.size_s() - 1;
@@ -569,7 +561,7 @@ bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) {
} }
// TileInput
TileInput::TileInput(const PIString & n): PIScreenTile(n) { TileInput::TileInput(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse; focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
@@ -591,10 +583,8 @@ void TileInput::sizeHint(int & w, int & h) const {
void TileInput::drawEvent(PIScreenDrawer * d) { void TileInput::drawEvent(PIScreenDrawer * d) {
PIString ps = text.mid(offset, width_ - 2); PIString ps = text.mid(offset, width_ - 2);
d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags); d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags);
if (offset > 0) if (offset > 0) d->drawText(x_, y_, "<", Green, Black, Bold);
d->drawText(x_, y_, "<", Green, Black, Bold); if (text.size_s() - offset >= width_ - 2) d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold);
if (text.size_s() - offset >= width_ - 2)
d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold);
if (!has_focus) return; if (!has_focus) return;
Color cb = (Color)format.color_char, cc = (Color)format.color_back; Color cb = (Color)format.color_char, cc = (Color)format.color_back;
if (tm_blink.elapsed_m() >= 650) { if (tm_blink.elapsed_m() >= 650) {
@@ -647,8 +637,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::Backspace: case PIKbdListener::Backspace:
if (cur > text.size_s() || text.isEmpty()) if (cur > text.size_s() || text.isEmpty()) return true;
return true;
text.remove(cur - 1, 1); text.remove(cur - 1, 1);
cur--; cur--;
if (cur > text.size_s()) cur = text.size_s(); if (cur > text.size_s()) cur = text.size_s();
@@ -658,8 +647,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor(); reserCursor();
return true; return true;
case PIKbdListener::Delete: case PIKbdListener::Delete:
if (cur >= text.size_s() || text.isEmpty()) if (cur >= text.size_s() || text.isEmpty()) return true;
return true;
text.remove(cur, 1); text.remove(cur, 1);
if (cur < 0) cur = 0; if (cur < 0) cur = 0;
if (cur > text.size_s()) cur = text.size_s(); if (cur > text.size_s()) cur = text.size_s();
@@ -685,8 +673,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
case PIKbdListener::F9: case PIKbdListener::F9:
case PIKbdListener::F10: case PIKbdListener::F10:
case PIKbdListener::F11: case PIKbdListener::F11:
case PIKbdListener::F12: case PIKbdListener::F12: break;
break;
default: default:
text.insert(cur, PIChar((ushort)key.key)); text.insert(cur, PIChar((ushort)key.key));
cur++; cur++;

View File

@@ -16,17 +16,19 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piincludes_p.h"
#include "piterminal.h" #include "piterminal.h"
#include "piincludes_p.h"
#include "piliterals_time.h"
#include "pisharedmemory.h" #include "pisharedmemory.h"
#ifndef MICRO_PIP #ifndef MICRO_PIP
# ifdef WINDOWS # ifdef WINDOWS
# include <windows.h> # include <windows.h>
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h>
# include <winuser.h> # include <winuser.h>
# else # else
# include "piprocess.h" # include "piprocess.h"
# include <csignal> # include <csignal>
# include <fcntl.h> # include <fcntl.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
@@ -123,9 +125,8 @@ PITerminal::PITerminal(): PIThread() {
PITerminal::~PITerminal() { PITerminal::~PITerminal() {
if (isRunning()) if (isRunning()) stop();
stop(); PIThread::waitForFinish(1_s);
PIThread::waitForFinish(10);
destroy(); destroy();
# ifdef WINDOWS # ifdef WINDOWS
if (PRIVATE->shm) delete PRIVATE->shm; if (PRIVATE->shm) delete PRIVATE->shm;
@@ -146,7 +147,8 @@ void PITerminal::write(const PIByteArray & d) {
if (PRIVATE->fd == 0) return; if (PRIVATE->fd == 0) return;
// ssize_t wrote = 0; // ssize_t wrote = 0;
// wrote = // wrote =
::write(PRIVATE->fd, d.data(), d.size_s()); auto _r = ::write(PRIVATE->fd, d.data(), d.size_s());
NO_UNUSED(_r);
// piCout << "wrote" << wrote << d; // piCout << "wrote" << wrote << d;
# endif # endif
# endif # endif
@@ -165,7 +167,8 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
default: break; default: break;
} }
// piCout << "write" << ba.size(); // piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba); if (!ba.isEmpty())
write(ba);
else { else {
PIByteArray msg; PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke; PIVector<PIKbdListener::KeyEvent> ke;
@@ -185,7 +188,8 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::UpArrow: case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow: case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow: case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1; case PIKbdListener::LeftArrow:
if (PRIVATE->DEC.value(CKM, false)) flags = 1;
/*case PIKbdListener::Home: //break; /*case PIKbdListener::Home: //break;
case PIKbdListener::End: //break; case PIKbdListener::End: //break;
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break; case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
@@ -235,7 +239,8 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
void PITerminal::write(PIKbdListener::KeyEvent ke) { void PITerminal::write(PIKbdListener::KeyEvent ke) {
if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers); if (isSpecialKey(ke.key))
write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
else { else {
PIByteArray ba; PIByteArray ba;
# ifdef WINDOWS # ifdef WINDOWS
@@ -253,8 +258,7 @@ PIVector<PIVector<PIScreenTypes::Cell> > PITerminal::content() {
PIVector<PIVector<PIScreenTypes::Cell>> ret = cells; PIVector<PIVector<PIScreenTypes::Cell>> ret = cells;
if (cursor_blink && cursor_visible) if (cursor_blink && cursor_visible)
if (cursor_x >= 0 && cursor_x < size_x) if (cursor_x >= 0 && cursor_x < size_x)
if (cursor_y >= 0 && cursor_y < size_y) if (cursor_y >= 0 && cursor_y < size_y) ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
return ret; return ret;
} }
@@ -395,16 +399,15 @@ void PITerminal::run() {
} }
bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE; bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE;
if (PRIVATE->read_buf.size_s() == 1) if (PRIVATE->read_buf.size_s() == 1)
if (PRIVATE->read_buf[0] < 0x80) if (PRIVATE->read_buf[0] < 0x80) parse = true;
parse = true;
if (parse) { if (parse) {
parseInput(PIString(PRIVATE->read_buf)); parseInput(PIString::fromUTF8(PRIVATE->read_buf));
PRIVATE->read_buf.clear(); PRIVATE->read_buf.clear();
} }
// printf("%s", PRIVATE->read_buf.data()); // printf("%s", PRIVATE->read_buf.data());
} }
if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) { if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) {
parseInput(PIString(PRIVATE->read_buf)); parseInput(PIString::fromUTF8(PRIVATE->read_buf));
PRIVATE->read_buf.clear(); PRIVATE->read_buf.clear();
} }
PRIVATE->last_read = false; PRIVATE->last_read = false;
@@ -445,7 +448,8 @@ void PITerminal::parseInput(const PIString & s) {
if (s[i] == '\r') continue; if (s[i] == '\r') continue;
if (s[i] == '\n') { if (s[i] == '\n') {
// piCoutObj << "new line"; // piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format; for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
moveCursor(0, 1); moveCursor(0, 1);
@@ -498,7 +502,8 @@ void PITerminal::applyEscSeq(PIString es) {
case 1047: case 1047:
if (val) { if (val) {
PRIVATE->cells_save = cells; PRIVATE->cells_save = cells;
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell); for (int i = 0; i < size_y; ++i)
cells[i].fill(def_cell);
} else { } else {
cells = PRIVATE->cells_save; cells = PRIVATE->cells_save;
} }
@@ -513,7 +518,7 @@ void PITerminal::applyEscSeq(PIString es) {
return; return;
} }
PIStringList args = es.split(";"); PIStringList args = es.split(";");
piForeachC (PIString & a, args) { for (const auto & a: args) {
int av = a.toInt(); int av = a.toInt();
switch (av) { switch (av) {
case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break; case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break;
@@ -524,8 +529,14 @@ void PITerminal::applyEscSeq(PIString es) {
default: { default: {
bool col = false, target = false; bool col = false, target = false;
int cid = av % 10; int cid = av % 10;
if (av >= 30 && av <= 37) {col = true; target = false;} if (av >= 30 && av <= 37) {
if (av >= 40 && av <= 47) {col = true; target = true;} col = true;
target = false;
}
if (av >= 40 && av <= 47) {
col = true;
target = true;
}
if (col) { if (col) {
int cfl = 0; int cfl = 0;
switch (cid) { switch (cid) {
@@ -586,25 +597,29 @@ void PITerminal::applyEscSeq(PIString es) {
} }
if (es.back() == 'A') { // cursor up if (es.back() == 'A') { // cursor up
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'B') { // cursor down if (es.back() == 'B') { // cursor down
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1); PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'D') { // cursor back if (es.back() == 'D') { // cursor back
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1); PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
@@ -616,65 +631,91 @@ void PITerminal::applyEscSeq(PIString es) {
} }
if (es.back() == 'd') { // goto line if (es.back() == 'd') { // goto line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1); PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'E' || es.back() == 'e') { // next line if (es.back() == 'E' || es.back() == 'e') { // next line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'F') { // previous line if (es.back() == 'F') { // previous line
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0; PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format; PRIVATE->line_format = PRIVATE->cur_format;
} }
if (es.back() == 'L') { // insert lines if (es.back() == 'L') { // insert lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); --i) cells[i] = cells[i - v]; if (v == 0) v = 1;
for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); ++j) for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1);
for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell; i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1);
--i)
cells[i] = cells[i - v];
for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1);
++j)
for (int i = 0; i < PRIVATE->cur_x; ++i)
cells[j][i] = def_cell;
} }
if (es.back() == 'M') { // delete lines if (es.back() == 'M') { // delete lines
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); ++i) cells[i] = cells[i + v]; if (v == 0) v = 1;
for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1);
++i)
cells[i] = cells[i + v];
for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j) for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j)
for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell; for (int i = 0; i < PRIVATE->cur_x; ++i)
cells[j][i] = def_cell;
} }
if (es.back() == 'P') { // delete characters if (es.back() == 'P') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
for (int i = PRIVATE->cur_x; i < size_x - v; ++i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v]; if (v == 0) v = 1;
for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; for (int i = PRIVATE->cur_x; i < size_x - v; ++i)
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v];
for (int i = size_x - v; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
} }
if (es.back() == '@') { // delete characters if (es.back() == '@') { // delete characters
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1; int v = es.toInt();
for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v]; if (v == 0) v = 1;
for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell; for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i)
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v];
for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
} }
if (es.back() == 'J') { // erase data if (es.back() == 'J') { // erase data
es.cutLeft(1).cutRight(1); es.cutLeft(1).cutRight(1);
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; for (int i = PRIVATE->cur_x; i < size_x; ++i)
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell); cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i)
cells[i].fill(def_cell);
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; for (int i = 0; i <= PRIVATE->cur_x; ++i)
for (int i = 0; i < PRIVATE->cur_y; ++i) cells[i].fill(def_cell); cells[PRIVATE->cur_y][i] = def_cell;
for (int i = 0; i < PRIVATE->cur_y; ++i)
cells[i].fill(def_cell);
break; break;
case 2: case 2:
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell); for (int i = 0; i < size_y; ++i)
cells[i].fill(def_cell);
// PRIVATE->cur_x = PRIVATE->cur_y = 0; // PRIVATE->cur_x = PRIVATE->cur_y = 0;
break; break;
} }
@@ -684,14 +725,14 @@ void PITerminal::applyEscSeq(PIString es) {
int v = es.toInt(); int v = es.toInt();
switch (v) { switch (v) {
case 0: case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
break; break;
case 1: case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; for (int i = 0; i <= PRIVATE->cur_x; ++i)
break; cells[PRIVATE->cur_y][i] = def_cell;
case 2:
cells[PRIVATE->cur_y].fill(def_cell);
break; break;
case 2: cells[PRIVATE->cur_y].fill(def_cell); break;
} }
} }
} }
@@ -721,8 +762,10 @@ void PITerminal::moveCursor(int dx, int dy) {
int PITerminal::termType(const PIString & t) { int PITerminal::termType(const PIString & t) {
if (t == "xterm") return PIKbdListener::vt_xterm; if (t == "xterm")
else if (t == "linux") return PIKbdListener::vt_linux; return PIKbdListener::vt_xterm;
else if (t == "linux")
return PIKbdListener::vt_linux;
return PIKbdListener::vt_none; return PIKbdListener::vt_none;
} }
# endif # endif
@@ -750,7 +793,7 @@ bool PITerminal::initialize() {
// SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0); // SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
// SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0); // SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
// GetStartupInfoA(&PRIVATE->si); // GetStartupInfoA(&PRIVATE->si);
memset(&PRIVATE->si, 0, sizeof(PRIVATE->si)); piZeroMemory(PRIVATE->si);
PRIVATE->si.cb = sizeof(STARTUPINFO); PRIVATE->si.cb = sizeof(STARTUPINFO);
// PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES; // PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW; PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
@@ -762,17 +805,33 @@ bool PITerminal::initialize() {
PRIVATE->si.dwXCountChars = 80; PRIVATE->si.dwXCountChars = 80;
PRIVATE->si.dwYCountChars = 24; PRIVATE->si.dwYCountChars = 24;
memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi)); piZeroMemory(PRIVATE->pi);
PIString shmh = PIString::fromNumber(randomi() % 10000); PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString pname = "\\\\.\\pipe\\piterm" + shmh; PIString pname = "\\\\.\\pipe\\piterm" + shmh;
PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\""; PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) { if (!CreateProcessA(0,
(LPSTR)cmd.dataAscii(),
0,
0,
false,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
0,
0,
&PRIVATE->si,
&PRIVATE->pi)) {
piCoutObj << "CreateProcess error," << errorString(); piCoutObj << "CreateProcess error," << errorString();
destroy(); destroy();
return false; return false;
} }
PRIVATE->pipe = CreateNamedPipe((LPSTR)pname.dataAscii(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 1000, NULL); PRIVATE->pipe = CreateNamedPipeA((LPSTR)pname.dataAscii(),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
2,
PIPE_BUFFER_SIZE,
PIPE_BUFFER_SIZE,
1000,
NULL);
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) { if (PRIVATE->pipe == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateNamedPipe error," << errorString(); piCoutObj << "CreateNamedPipe error," << errorString();
destroy(); destroy();
@@ -797,12 +856,13 @@ bool PITerminal::initialize() {
resize(dsize_x, dsize_y); resize(dsize_x, dsize_y);
# else # else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
char pty[256]; memset(pty, 0, 256); char pty[256];
piZeroMemory(pty, 256);
winsize ws; winsize ws;
ws.ws_col = dsize_x; ws.ws_col = dsize_x;
ws.ws_row = dsize_y; ws.ws_row = dsize_y;
PIStringList env = PIProcess::currentEnvironment(); PIStringList env = PIProcess::currentEnvironment();
piForeachC (PIString & e, env) for (const auto & e: env)
if (e.startsWith("TERM=")) { if (e.startsWith("TERM=")) {
PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase()); PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase());
// piCout << PRIVATE->term_type; // piCout << PRIVATE->term_type;
@@ -856,7 +916,7 @@ bool PITerminal::initialize() {
# endif # endif
cursor_blink = false; cursor_blink = false;
cursor_tm.reset(); cursor_tm.reset();
start(40); start(25_Hz);
return true; return true;
} }
@@ -864,7 +924,7 @@ bool PITerminal::initialize() {
void PITerminal::destroy() { void PITerminal::destroy() {
// piCout << "destroy ..."; // piCout << "destroy ...";
stop(); stop();
waitForFinish(1000); waitForFinish(1_s);
# ifdef WINDOWS # ifdef WINDOWS
if (PRIVATE->pi.hProcess) { if (PRIVATE->pi.hProcess) {
// piCout << "term"; // piCout << "term";
@@ -877,10 +937,8 @@ void PITerminal::destroy() {
// piCout << "destroy" << size_y; // piCout << "destroy" << size_y;
# else # else
# ifdef HAS_FORKPTY # ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL);
kill(PRIVATE->pid, SIGKILL); if (PRIVATE->fd != 0) ::close(PRIVATE->fd);
if (PRIVATE->fd != 0)
::close(PRIVATE->fd);
# endif # endif
# endif # endif
initPrivate(); initPrivate();

View File

@@ -238,7 +238,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
rinfo = crypt.decrypt(rinfo, secret_key, &ok); rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys"); if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected; state = Connected;
connected(rinfo); connected(PIString::fromUTF8(rinfo));
ba << (int)state << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE); ba << (int)state << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
return state; return state;
} }

View File

@@ -18,26 +18,31 @@
*/ */
#include "picrypt.h" #include "picrypt.h"
#ifdef PIP_CRYPT
#include "pitranslator.h"
#include <sodium.h> #include <sodium.h>
#endif
#define PICRYPT_DISABLED_WARNING piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
const char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0"; namespace {
const int hash_def_key_size = 9; constexpr char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
constexpr int hash_def_key_size = 9;
} // namespace
PICrypt::PICrypt() { PICrypt::PICrypt() {
#ifdef PIP_CRYPT if (!init()) {
if (!init()) piCout << "[PICrypt]" << "Error while initialize sodium!"; piCout << "[PICrypt]"
<< "Error while initialize sodium!"_tr("PICrypt");
}
nonce_.resize(crypto_secretbox_NONCEBYTES); nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES); key_.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(key_.data(), key_.size()); randombytes_buf(key_.data(), key_.size());
randombytes_buf(nonce_.data(), nonce_.size()); randombytes_buf(nonce_.data(), nonce_.size());
#else }
PICRYPT_DISABLED_WARNING
#endif PICrypt::~PICrypt() {
key_.fill(0);
nonce_.fill(0);
} }
@@ -48,401 +53,324 @@ bool PICrypt::setKey(const PIByteArray & _key) {
} }
PIByteArray PICrypt::setKey(const PIString & secret) { bool PICrypt::setKey(const PIString & secret) {;
PIByteArray hash; key_ = hash(secret);
#ifdef PIP_CRYPT return key_.isNotEmpty();
hash.resize(crypto_generichash_BYTES);
PIByteArray s(secret.data(), secret.size());
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar*)hash_def_key, hash_def_key_size);
hash.resize(key_.size());
setKey(hash);
#endif
return hash;
} }
PIByteArray PICrypt::crypt(const PIByteArray & data) { PIByteArray PICrypt::crypt(const PIByteArray & data) {
PIByteArray ret; PIByteArray ret;
#ifdef PIP_CRYPT
ret.resize(data.size() + crypto_secretbox_MACBYTES); ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(nonce_.data(), nonce_.size()); randombytes_buf(nonce_.data(), nonce_.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data()); if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data()) != 0) {
ret.clear();
} else {
ret.append(nonce_); ret.append(nonce_);
#endif }
return ret; return ret;
} }
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) { PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
PIByteArray ret; if (!init()) {
#ifdef PIP_CRYPT key.fill(0);
if (key.size() != crypto_secretbox_KEYBYTES) return PIByteArray();
key.resize(crypto_secretbox_KEYBYTES, ' '); }
//return PIByteArray(); if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' ');
if (!init()) return ret;
PIByteArray n; PIByteArray n;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
n.resize(crypto_secretbox_NONCEBYTES); n.resize(crypto_secretbox_NONCEBYTES);
PIByteArray ret;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(n.data(), n.size()); randombytes_buf(n.data(), n.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data()); if (crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data()) != 0) {
ret.clear();
} else {
ret.append(n); ret.append(n);
#else }
PICRYPT_DISABLED_WARNING key.fill(0);
#endif
return ret; return ret;
} }
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) { if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
if (ok) *ok = false; if (ok) *ok = false;
return PIByteArray(); return PIByteArray();
} }
ret.resize(crypt_data.size() - nonce_.size() - crypto_secretbox_MACBYTES); const ullong data_size = crypt_data.size() - nonce_.size();
memcpy(nonce_.data(), crypt_data.data(crypt_data.size() - nonce_.size()), nonce_.size()); PIByteArray ret;
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - nonce_.size(), nonce_.data(), key_.data()) != 0) { ret.resize(data_size - crypto_secretbox_MACBYTES);
memcpy(nonce_.data(), crypt_data.data(data_size), nonce_.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, nonce_.data(), key_.data()) != 0) {
// Bad key
if (ok) *ok = false; if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_"; ret.clear();
return PIByteArray(); } else if (ok) {
*ok = true;
} }
#endif
if (ok) *ok = true;
return ret; return ret;
} }
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok) {
PIByteArray ret; if (!init()) {
#ifdef PIP_CRYPT key.fill(0);
if (key.size() != crypto_secretbox_KEYBYTES)
key.resize(crypto_secretbox_KEYBYTES, ' ');
/*if (ok) *ok = false;
return PIByteArray();
}*/
if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
return PIByteArray(); return PIByteArray();
} }
if (!init()) return ret; if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
key.fill(0);
return PIByteArray();
}
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' ');
PIByteArray n; PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES); n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES); const ullong data_size = crypt_data.size() - n.size();
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size()); PIByteArray ret;
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) { ret.resize(data_size - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), key.data()) != 0) {
// Bad key
if (ok) *ok = false; if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_"; ret.clear();
return PIByteArray(); } else if (ok) {
} else if (ok) *ok = true; *ok = true;
#else }
PICRYPT_DISABLED_WARNING key.fill(0);
#endif
return ret; return ret;
} }
PIByteArray PICrypt::hash(const PIString & secret) { PIByteArray PICrypt::hash(PIString secret) {
PIByteArray hash; if (!init()) return {};
#ifdef PIP_CRYPT PIByteArray s = secret.toUTF8();
if (!init()) return hash; PIByteArray h = hash(s);
hash.resize(crypto_generichash_BYTES); memset(const_cast<char *>(secret.data()), 0, s.size());
PIByteArray s(secret.data(), secret.size()); secret.fill('\0');
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(),(const uchar*)hash_def_key, hash_def_key_size); s.fill(0);
#else return h;
PICRYPT_DISABLED_WARNING
#endif
return hash;
} }
PIByteArray PICrypt::hash(const PIByteArray & data) { PIByteArray PICrypt::hash(const PIByteArray & data) {
PIByteArray hash; if (!init()) return {};
#ifdef PIP_CRYPT PIByteArray h;
if (!init()) return hash; h.resize(crypto_generichash_BYTES);
hash.resize(crypto_generichash_BYTES); crypto_generichash(h.data(), h.size(), data.data(), data.size(), (const uchar *)hash_def_key, hash_def_key_size);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), (const uchar*)hash_def_key, hash_def_key_size); return h;
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
} }
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char * key, size_t keylen) { PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char * key, size_t keylen) {
PIByteArray hash; PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash; if (!init()) return hash;
hash.resize(crypto_generichash_BYTES); hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen); crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash; return hash;
} }
size_t PICrypt::sizeHash() { size_t PICrypt::sizeHash() {
#ifdef PIP_CRYPT
return crypto_generichash_BYTES; return crypto_generichash_BYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
} }
ullong PICrypt::shorthash(const PIString & s, PIByteArray key) { ullong PICrypt::shorthash(const PIString & s, PIByteArray key) {
ullong hash = 0; ullong hash = 0;
#ifdef PIP_CRYPT if (!init()) {
if (crypto_shorthash_BYTES != sizeof(hash)) piCout << "[PICrypt]" << "internal error: bad hash size"; key.fill(0);
if (!init()) return hash; return hash;
}
if (crypto_shorthash_BYTES != sizeof(hash))
piCout << "[PICrypt]"
<< "internal error: bad hash size"_tr("PICrypt");
if (key.size() != crypto_shorthash_KEYBYTES) { if (key.size() != crypto_shorthash_KEYBYTES) {
piCout << "[PICrypt]" << "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros"; piCout << "[PICrypt]"
<< "invalid key size %1, should be %2, filled with zeros"_tr("PICrypt").arg(key.size()).arg(crypto_shorthash_KEYBYTES);
key.resize(crypto_shorthash_KEYBYTES, 0); key.resize(crypto_shorthash_KEYBYTES, 0);
} }
PIByteArray in(s.data(), s.size()); PIByteArray in(s.data(), s.size());
crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data()); crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
#else key.fill(0);
PICRYPT_DISABLED_WARNING
#endif
return hash; return hash;
} }
PIByteArray PICrypt::generateKey() { PIByteArray PICrypt::generateKey() {
PIByteArray hash; return generateRandomBuff(sizeKey());
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(hash.data(), hash.size());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
} }
PIByteArray PICrypt::generateRandomBuff(int size) { PIByteArray PICrypt::generateRandomBuff(int size) {
PIByteArray hash; PIByteArray hash;
#ifdef PIP_CRYPT
if (!init() || size <= 0) return hash; if (!init() || size <= 0) return hash;
hash.resize(size); hash.resize(size);
randombytes_buf(hash.data(), hash.size()); randombytes_buf(hash.data(), hash.size());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash; return hash;
} }
size_t PICrypt::sizeKey() { size_t PICrypt::sizeKey() {
#ifdef PIP_CRYPT
return crypto_secretbox_KEYBYTES; return crypto_secretbox_KEYBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
} }
size_t PICrypt::sizeCrypt() { size_t PICrypt::sizeCrypt() {
#ifdef PIP_CRYPT
return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
} }
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) { bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT if (!init()) return false;
if (!init()) return;
public_key.resize(crypto_sign_PUBLICKEYBYTES); public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES); secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_keypair(public_key.data(), secret_key.data()); return crypto_sign_keypair(public_key.data(), secret_key.data()) == 0;
#else
PICRYPT_DISABLED_WARNING
#endif
} }
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { bool PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT if (!init() || seed.isEmpty()) return false;
if (!init() || seed.isEmpty()) return;
public_key.resize(crypto_sign_PUBLICKEYBYTES); public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES); secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()); return crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0;
#else
PICRYPT_DISABLED_WARNING
#endif
} }
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) { PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) {
PIByteArray pk; PIByteArray pk;
#ifdef PIP_CRYPT
if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk; if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk;
pk.resize(crypto_sign_PUBLICKEYBYTES); pk.resize(crypto_sign_PUBLICKEYBYTES);
crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data()); if (crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data()) != 0) {
#else pk.clear();
PICRYPT_DISABLED_WARNING }
#endif
return pk; return pk;
} }
PIByteArray PICrypt::signMessage(const PIByteArray & data, PIByteArray secret_key) { PIByteArray PICrypt::signMessage(const PIByteArray & data, const PIByteArray & secret_key) {
PIByteArray sign; PIByteArray sign;
#ifdef PIP_CRYPT
if (!init()) return sign; if (!init()) return sign;
sign.resize(crypto_sign_BYTES); sign.resize(crypto_sign_BYTES);
crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data()); if (crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data()) != 0) {
#else sign.clear();
PICRYPT_DISABLED_WARNING }
#endif
return sign; return sign;
} }
bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key) { bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, const PIByteArray & public_key) {
#ifdef PIP_CRYPT
if (!init()) return false; if (!init()) return false;
return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0); return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0);
#else
PICRYPT_DISABLED_WARNING
#endif
return false; return false;
} }
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) { bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT if (!init()) return false;
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES); public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES); secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_keypair(public_key.data(), secret_key.data()); return crypto_box_keypair(public_key.data(), secret_key.data()) == 0;
#else
PICRYPT_DISABLED_WARNING
#endif
} }
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) { bool PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT if (!init()) return false;
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES); public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES); secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()); return crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data()) == 0;
#else
PICRYPT_DISABLED_WARNING
#endif
} }
PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) { PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) {
PIByteArray ret; if (!init()) return PIByteArray();
#ifdef PIP_CRYPT if (public_key.size() != crypto_box_PUBLICKEYBYTES) return PIByteArray();
if (!init()) return ret; if (secret_key.size() != crypto_box_SECRETKEYBYTES) return PIByteArray();
if (public_key.size() != crypto_box_PUBLICKEYBYTES)
return ret;
if (secret_key.size() != crypto_box_SECRETKEYBYTES)
return ret;
PIByteArray n; PIByteArray n;
ret.resize(data.size() + crypto_box_MACBYTES);
n.resize(crypto_box_NONCEBYTES); n.resize(crypto_box_NONCEBYTES);
PIByteArray ret;
ret.resize(data.size() + crypto_box_MACBYTES);
randombytes_buf(n.data(), n.size()); randombytes_buf(n.data(), n.size());
if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0) if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
return PIByteArray(); return PIByteArray();
}
ret.append(n); ret.append(n);
#else
PICRYPT_DISABLED_WARNING
#endif
return ret; return ret;
} }
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) { PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) {
PIByteArray ret; if (!init()) {
#ifdef PIP_CRYPT if (ok) *ok = false;
if (!init()) return ret; return PIByteArray();
}
if (public_key.size() != crypto_box_PUBLICKEYBYTES) { if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
if (ok) *ok = false; if (ok) *ok = false;
return ret; return PIByteArray();
} }
if (secret_key.size() != crypto_box_SECRETKEYBYTES) { if (secret_key.size() != crypto_box_SECRETKEYBYTES) {
if (ok) *ok = false; if (ok) *ok = false;
return ret; return PIByteArray();
} }
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) { if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) {
if (ok) *ok = false; if (ok) *ok = false;
return ret; return PIByteArray();
} }
PIByteArray n; PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES); n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES); const ullong data_size = crypt_data.size() - n.size();
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size()); PIByteArray ret;
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) != 0) { ret.resize(data_size - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(data_size), n.size());
if (crypto_box_open_easy(ret.data(), crypt_data.data(), data_size, n.data(), public_key.data(), secret_key.data()) != 0) {
// Bad key
if (ok) *ok = false; if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_"; ret.clear();
return PIByteArray(); } else if (ok) {
} else if (ok) *ok = true; *ok = true;
#else }
PICRYPT_DISABLED_WARNING
#endif
return ret; return ret;
} }
PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray & seed) { PIByteArray PICrypt::passwordHash(PIString password, const PIByteArray & seed) {
#ifdef crypto_pwhash_ALG_ARGON2I13 #ifdef crypto_pwhash_ALG_ARGON2I13
// char out[crypto_pwhash_STRBYTES];
PIByteArray pass = password.toUTF8(); PIByteArray pass = password.toUTF8();
PIByteArray n = hash(seed); PIByteArray n = hash(seed);
PIByteArray ph; PIByteArray ph;
ph.resize(crypto_box_SEEDBYTES); ph.resize(crypto_box_SEEDBYTES);
n.resize(crypto_pwhash_SALTBYTES); n.resize(crypto_pwhash_SALTBYTES);
// randombytes_buf(n.data(), n.size()); int r = crypto_pwhash(ph.data(),
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data()); ph.size(),
int r = crypto_pwhash(ph.data(), ph.size(), (const char*)pass.data(), pass.size(), n.data(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate(), crypto_pwhash_ALG_ARGON2I13); (const char *)pass.data(),
//crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate()); pass.size(),
n.data(),
crypto_pwhash_argon2i_opslimit_moderate(),
crypto_pwhash_argon2i_memlimit_moderate(),
crypto_pwhash_ALG_ARGON2I13);
pass.fill(0); pass.fill(0);
memset(const_cast<char *>(password.data()), 0, pass.size());
password.fill('\0');
if (r != 0) return PIByteArray(); if (r != 0) return PIByteArray();
return ph; return ph;
// PIByteArray ret;
// ret << ph << n << crypto_pwhash_argon2i_opslimit_moderate() << crypto_pwhash_argon2i_memlimit_moderate();
// return ret;
#else #else
piCout << "[PICrypt] Error, ALG_ARGON2I13 not availible!";
return PIByteArray(); return PIByteArray();
#endif #endif
} }
PIString PICrypt::version() { PIString PICrypt::version() {
#ifdef PIP_CRYPT
return SODIUM_VERSION_STRING; return SODIUM_VERSION_STRING;
#else
return PIString();
#endif
} }
bool PICrypt::init() { bool PICrypt::init() {
#ifdef PIP_CRYPT
static bool inited = false; static bool inited = false;
if (inited) return true; if (inited) return true;
// piCout << "[PICrypt]" << "init ..."; // piCout << "[PICrypt]" << "init ...";
inited = sodium_init(); inited = sodium_init();
if (!inited) if (!inited) inited = sodium_init();
inited = sodium_init();
// piCout << "[PICrypt]" << "init" << inited; // piCout << "[PICrypt]" << "init" << inited;
return inited; return inited;
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
} }

View File

@@ -18,16 +18,30 @@
*/ */
#include "pifft.h" #include "pifft.h"
#include "pifft_p.h" #include "pifft_p.h"
#define _PIFFTW_CPP(type) \ #define _PIFFTW_CPP(type) \
_PIFFTW_P_##type##_::_PIFFTW_P_##type##_() {impl = new PIFFTW_Private<type>();;} \ _PIFFTW_P_##type##_::_PIFFTW_P_##type##_() { \
_PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() {delete (PIFFTW_Private<type>*)impl;} \ impl = new PIFFTW_Private<type>(); \
const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFT(const PIVector<complex<type> > & in) {return ((PIFFTW_Private<type>*)impl)->calcFFT(in);} \ ; \
const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFTR(const PIVector<type> & in) {return ((PIFFTW_Private<type>*)impl)->calcFFT(in);} \ } \
const PIVector<complex<type> > & _PIFFTW_P_##type##_::calcFFTI(const PIVector<complex<type> > & in) {return ((PIFFTW_Private<type>*)impl)->calcFFTinverse(in);} \ _PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() { \
void _PIFFTW_P_##type##_::preparePlan(int size, int op) {return ((PIFFTW_Private<type>*)impl)->preparePlan(size, op);} delete (PIFFTW_Private<type> *)impl; \
} \
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFT(const PIVector<complex<type>> & in) { \
return ((PIFFTW_Private<type> *)impl)->calcFFT(in); \
} \
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFTR(const PIVector<type> & in) { \
return ((PIFFTW_Private<type> *)impl)->calcFFT(in); \
} \
const PIVector<complex<type>> & _PIFFTW_P_##type##_::calcFFTI(const PIVector<complex<type>> & in) { \
return ((PIFFTW_Private<type> *)impl)->calcFFTinverse(in); \
} \
void _PIFFTW_P_##type##_::preparePlan(int size, int op) { \
return ((PIFFTW_Private<type> *)impl)->preparePlan(size, op); \
}
_PIFFTW_CPP(float) _PIFFTW_CPP(float)
_PIFFTW_CPP(double) _PIFFTW_CPP(double)

View File

@@ -23,8 +23,9 @@
#ifndef PIFFT_P_H #ifndef PIFFT_P_H
#define PIFFT_P_H #define PIFFT_P_H
#include "pivector.h"
#include "picout.h" #include "picout.h"
#include "pimathcomplex.h"
#include "pivector.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq) #if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h" # include "fftw3.h"
#else #else
@@ -36,8 +37,7 @@
template<typename T> template<typename T>
class PIFFTW_Private class PIFFTW_Private {
{
public: public:
explicit PIFFTW_Private() { explicit PIFFTW_Private() {
plan = 0; plan = 0;
@@ -51,7 +51,7 @@ public:
const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) { const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) {
if (prepare != PlanParams(in.size(), fo_complex)) { if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size()); p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan"; // piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex); prepare = PlanParams(in.size(), fo_complex);
} }
@@ -61,7 +61,7 @@ public:
const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) { const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) { if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size()); p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan"; // piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real); prepare = PlanParams(in.size(), fo_real);
} }
@@ -71,7 +71,7 @@ public:
const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) { const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) { if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size()); p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan"; // piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse); prepare = PlanParams(in.size(), fo_inverse);
} }
@@ -79,7 +79,11 @@ public:
return p_out; return p_out;
} }
enum FFT_Operation {fo_real, fo_complex, fo_inverse}; enum FFT_Operation {
fo_real,
fo_complex,
fo_inverse
};
void preparePlan(int size, int op) { void preparePlan(int size, int op) {
p_inr.clear(); p_inr.clear();
@@ -101,9 +105,7 @@ public:
p_out.resize(size); p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED); p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break; break;
default: default: size = 0; break;
size = 0;
break;
} }
prepare = PlanParams(size, (FFT_Operation)op); prepare = PlanParams(size, (FFT_Operation)op);
} }
@@ -117,8 +119,14 @@ public:
inline void p_makeThreadSafe() {} inline void p_makeThreadSafe() {}
struct PlanParams { struct PlanParams {
PlanParams() {size = 0; op = fo_complex;} PlanParams() {
PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;} size = 0;
op = fo_complex;
}
PlanParams(int size_, FFT_Operation op_) {
size = size_;
op = op_;
}
bool isValid() { return size > 0; } bool isValid() { return size > 0; }
bool operator==(const PlanParams & v) const { return (v.size == size) && (v.op == op); } bool operator==(const PlanParams & v) const { return (v.size == size) && (v.op == op); }
bool operator!=(const PlanParams & v) const { return !(*this == v); } bool operator!=(const PlanParams & v) const { return !(*this == v); }
@@ -135,44 +143,104 @@ public:
#ifdef PIP_FFTWf #ifdef PIP_FFTWf
template<> inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { template<>
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);} inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
template<> inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);
plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags);} }
template<> inline void PIFFTW_Private<float>::p_executePlan(void * plan) {fftwf_execute((fftwf_plan)plan);} template<>
template<> inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out);} inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
template<> inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);} plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags);
template<> inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {if (plan) fftwf_destroy_plan((fftwf_plan)plan); plan = 0;} }
template<>
inline void PIFFTW_Private<float>::p_executePlan(void * plan) {
fftwf_execute((fftwf_plan)plan);
}
template<>
inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out);
}
template<>
inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);
}
template<>
inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {
if (plan) fftwf_destroy_plan((fftwf_plan)plan);
plan = 0;
}
# ifdef PIP_FFTWf_THREADSAFE # ifdef PIP_FFTWf_THREADSAFE
template<> inline void PIFFTW_Private<float>::p_makeThreadSafe() {fftwf_make_planner_thread_safe();} template<>
inline void PIFFTW_Private<float>::p_makeThreadSafe() {
fftwf_make_planner_thread_safe();
}
# endif # endif
#endif // PIP_FFTWf #endif // PIP_FFTWf
#ifdef PIP_FFTW #ifdef PIP_FFTW
template<> inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { template<>
plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);} inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
template<> inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);
plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);} }
template<> inline void PIFFTW_Private<double>::p_executePlan(void * plan) {fftw_execute((fftw_plan)plan);} template<>
template<> inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);} inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
template<> inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);} plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);
template<> inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {if (plan) fftw_destroy_plan((fftw_plan)plan); plan = 0;} }
template<>
inline void PIFFTW_Private<double>::p_executePlan(void * plan) {
fftw_execute((fftw_plan)plan);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {
if (plan) fftw_destroy_plan((fftw_plan)plan);
plan = 0;
}
# ifdef PIP_FFTW_THREADSAFE # ifdef PIP_FFTW_THREADSAFE
template<> inline void PIFFTW_Private<double>::p_makeThreadSafe() {fftw_make_planner_thread_safe();} template<>
inline void PIFFTW_Private<double>::p_makeThreadSafe() {
fftw_make_planner_thread_safe();
}
# endif # endif
#endif // PIP_FFTW #endif // PIP_FFTW
#ifdef PIP_FFTWl #ifdef PIP_FFTWl
template<> inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { template<>
plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);} inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
template<> inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);
plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);} }
template<> inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {fftwl_execute((fftwl_plan)plan);} template<>
template<> inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);} inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
template<> inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);} plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);
template<> inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {if (plan) fftwl_destroy_plan((fftwl_plan)plan); plan = 0;} }
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {
fftwl_execute((fftwl_plan)plan);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {
if (plan) fftwl_destroy_plan((fftwl_plan)plan);
plan = 0;
}
# ifdef PIP_FFTWl_THREADSAFE # ifdef PIP_FFTWl_THREADSAFE
template<> inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {fftwl_make_planner_thread_safe();} template<>
inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {
fftwl_make_planner_thread_safe();
}
# endif # endif
#endif // PIP_FFTWl #endif // PIP_FFTWl

View File

@@ -0,0 +1,77 @@
#include "curl_thread_pool_p.h"
#include "pihttpclient.h"
#include "pitime.h"
#include <curl/curl.h>
CurlThreadPool::CurlThreadPool() {
piForTimes(10) {
auto * t = new PIThread([this]() { threadFunc(); }, true);
threads << t;
}
}
CurlThreadPool::~CurlThreadPool() {
exiting = true;
for (auto * t: threads)
t->stop();
{
auto cr = clients.getRef();
for (auto c: *cr)
c->abort();
}
sem.release(threads.size());
for (auto * t: threads) {
t->waitForFinish();
t->setDebug(false);
t->terminate();
}
piDeleteAllAndClear(threads);
{
auto cr = clients.getRef();
for (auto c: *cr)
delete c;
}
curl_global_cleanup();
}
void CurlThreadPool::threadFunc() {
if (exiting) return;
// piCout << "threadFuncl w ...";
sem.acquire();
// piCout << "threadFuncl wdone";
if (exiting) return;
PIHTTPClient * c = nullptr;
{
auto cr = clients.getRef();
if (cr->isEmpty()) return;
c = cr->dequeue();
// piCout << "threadFuncl get c";
}
// piCout << "threadFuncl proc c";
procClient(c);
// piCout << "threadFuncl end";
}
void CurlThreadPool::procClient(PIHTTPClient * c) {
if (c->init()) c->perform();
delete c;
}
void CurlThreadPool::registerClient(PIHTTPClient * c) {
clients.getRef()->enqueue(c);
sem.release();
// piCout << "registerClient";
}
CurlThreadPool * CurlThreadPool::instance() {
static CurlThreadPool ret;
return &ret;
}

View File

@@ -0,0 +1,31 @@
#ifndef curl_thread_pool_p_H
#define curl_thread_pool_p_H
#include "piprotectedvariable.h"
#include "pisemaphore.h"
#include "pithread.h"
class PIHTTPClient;
class CurlThreadPool {
public:
void registerClient(PIHTTPClient * c);
static CurlThreadPool * instance();
private:
NO_COPY_CLASS(CurlThreadPool)
CurlThreadPool();
~CurlThreadPool();
void threadFunc();
void procClient(PIHTTPClient * c);
PIProtectedVariable<PIQueue<PIHTTPClient *>> clients;
PISemaphore sem;
PIVector<PIThread *> threads;
std::atomic_bool exiting = {false};
};
#endif

View File

@@ -0,0 +1,237 @@
#include "pihttpclient.h"
#include "curl_thread_pool_p.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "pisystemtime.h"
#include <curl/curl.h>
#if !defined(CURL_WRITEFUNC_ERROR)
# define CURL_WRITEFUNC_ERROR 0xFFFFFFFF
#endif
int xfer_callback(void * ptr, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int debug_callback(CURL * handle, curl_infotype type, char * data, size_t size, void * ptr) {
return reinterpret_cast<PIHTTPClientBase *>(ptr)->__debugFunc(type, data, size);
}
PRIVATE_DEFINITION_START(PIHTTPClient)
CURL * handle = nullptr;
curl_slist * header_list = nullptr;
PRIVATE_DEFINITION_END(PIHTTPClient)
PIHTTPClient::PIHTTPClient() {}
PIHTTPClient::~PIHTTPClient() {}
bool PIHTTPClient::init() {
if (is_cancel) return false;
PRIVATE->handle = curl_easy_init();
if (!PRIVATE->handle) return false;
auto ait = request.arguments().makeIterator();
while (ait.next()) {
if (!url.contains('?'))
url.append('?');
else
url.append('&');
url.append(ait.key().toPercentageEncoding());
url.append('=');
url.append(ait.value().toPercentageEncoding());
}
headers.clear();
auto hit = request.headers().makeIterator();
while (hit.next()) {
headers << hit.key() + ": " + hit.value();
}
for (const auto & h: headers)
PRIVATE->header_list = curl_slist_append(PRIVATE->header_list, h.dataAscii());
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERDATA, this);
curl_easy_setopt(PRIVATE->handle, CURLOPT_WRITEFUNCTION, writeMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_READFUNCTION, readMemoryFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_XFERINFOFUNCTION, xfer_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_DEBUGFUNCTION, debug_callback);
curl_easy_setopt(PRIVATE->handle, CURLOPT_HEADERFUNCTION, headerFunc);
curl_easy_setopt(PRIVATE->handle, CURLOPT_URL, url.dataUTF8());
curl_easy_setopt(PRIVATE->handle, CURLOPT_CUSTOMREQUEST, PIHTTP::methodName(request.method()));
curl_easy_setopt(PRIVATE->handle, CURLOPT_HTTPHEADER, PRIVATE->header_list);
curl_easy_setopt(PRIVATE->handle, CURLOPT_NOPROGRESS, 0L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_VERBOSE, 1L);
// curl_easy_setopt(PRIVATE->handle, CURLOPT_ERRORBUFFER, buffer_error.data());
curl_easy_setopt(PRIVATE->handle, CURLOPT_SSL_VERIFYPEER, 0L);
if (request.body().isNotEmpty()) {
curl_easy_setopt(PRIVATE->handle, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(PRIVATE->handle, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(request.body().size()));
}
return true;
}
void PIHTTPClient::perform() {
if (!PRIVATE->handle) return;
if (!is_cancel) {
// piCout << "perform ...";
PITimeMeasurer tm;
CURLcode res = curl_easy_perform(PRIVATE->handle);
// piCout << "done" << res << "in" << tm.elapsed_m() << ", bytes" << buffer_out.size();
if (res == CURLE_OK) {
reply.setBody(std::move(buffer_out));
if (on_finish) on_finish(reply);
} else {
if (res == CURLE_ABORTED_BY_CALLBACK || is_cancel) {
// piCerr << "curl_easy_perform() failed:" << curl_easy_strerror(res);
if (on_abort) on_abort(reply);
} else {
last_error = curl_easy_strerror(res);
if (on_error) on_error(reply);
}
}
}
// piCout << last_error;
if (PRIVATE->header_list) curl_slist_free_all(PRIVATE->header_list);
curl_easy_cleanup(PRIVATE->handle);
PRIVATE->handle = nullptr;
PRIVATE->header_list = nullptr;
}
void PIHTTPClient::procHeaderLine(PIString & line) {
if (line.startsWith("HTTP"_a)) {
// HTTP/Версия КодСостояния Пояснение
line.cutLeft(5);
line.takeWord();
int code = line.takeWord().toInt();
// piCout << "code" << code;
reply.setCode(static_cast<PIHTTP::Code>(code));
return;
}
int ind = line.find(':');
if (ind < 0) return;
PIString hname = line.takeLeft(ind);
line.cutLeft(1).trim();
reply.addHeader(hname, line);
}
size_t PIHTTPClient::writeMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "writeMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
client->buffer_out.append(contents, bytes);
return bytes;
}
size_t PIHTTPClient::readMemoryFunc(void * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
// piCout << "readMemoryFunc" << bytes;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_READFUNC_ABORT;
const auto & buffer(client->request.body());
if (buffer.isEmpty()) return 0;
// piCout << bytes;
ssize_t ret = piClamp<ssize_t>(bytes, 0, buffer.size_s() - client->read_pos);
if (ret < 0) ret = 0;
if (ret > 0) memcpy(contents, buffer.data(client->read_pos), ret);
return ret;
}
size_t PIHTTPClient::headerFunc(char * contents, size_t size, size_t nmemb, void * ptr) {
size_t bytes = size * nmemb;
auto client = reinterpret_cast<PIHTTPClient *>(ptr);
if (client->is_cancel) return CURL_WRITEFUNC_ERROR;
PIString line = PIString::fromUTF8(contents, bytes).trim();
if (line.isNotEmpty()) client->procHeaderLine(line);
return bytes;
}
int PIHTTPClient::infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
// piCout << "infoFunc" << dltotal << dlnow << ultotal << ulnow;
if (is_cancel) return 1;
return 0;
}
int PIHTTPClient::debugFunc(int type, char * data, size_t size) {
// piCout << "debugFunc" << type << PIString::fromUTF8(data, size);
return 0;
}
PIHTTPClient * PIHTTPClient::create(const PIString & url_, PIHTTP::Method method, const PIHTTP::MessageConst & req) {
PIHTTPClient * ret = new PIHTTPClient();
static_cast<PIHTTP::MessageConst &>(ret->request) = req;
ret->request.setMethod(method);
ret->reply.setMethod(method);
ret->url = url_;
return ret;
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void()> f) {
return onFinish([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onFinish(std::function<void(const PIHTTP::MessageConst &)> f) {
on_finish = f;
return this;
}
PIHTTPClient * PIHTTPClient::onError(std::function<void()> f) {
return onError([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onError(std::function<void(const PIHTTP::MessageConst &)> f) {
on_error = f;
return this;
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void()> f) {
return onAbort([f](const PIHTTP::MessageConst &) { f(); });
}
PIHTTPClient * PIHTTPClient::onAbort(std::function<void(const PIHTTP::MessageConst &)> f) {
on_abort = f;
return this;
}
void PIHTTPClient::start() {
CurlThreadPool::instance()->registerClient(this);
}
void PIHTTPClient::abort() {
is_cancel = true;
}
int PIHTTPClientBase::__infoFunc(ssize_t dltotal, ssize_t dlnow, ssize_t ultotal, ssize_t ulnow) {
return reinterpret_cast<PIHTTPClient *>(this)->infoFunc(dltotal, dlnow, ultotal, ulnow);
}
int PIHTTPClientBase::__debugFunc(int type, char * data, size_t size) {
return reinterpret_cast<PIHTTPClient *>(this)->debugFunc(type, data, size);
}

View File

@@ -0,0 +1,367 @@
#include "microhttpd_server.h"
#include "piliterals_bytes.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include <microhttpd.h>
// clang-format off
#ifdef QNX
# include <arpa/inet.h>
# include <sys/socket.h>
# include <sys/types.h>
# ifdef BLACKBERRY
# include <netinet/in.h>
# else
# include <sys/dcmd_io-net.h>
# endif
#else
# ifdef WINDOWS
# include <io.h>
# include <winsock2.h>
# include <ws2tcpip.h>
# else
# include <netinet/in.h>
# include <sys/socket.h>
# ifdef LWIP
# include <lwip/sockets.h>
# endif
# endif
#endif
// clang-format on
using namespace PIHTTP;
struct BasicAuthCred {
bool exists = false;
PIString user;
PIString pass;
};
struct MicrohttpdServerConnection {
bool checkBasicAuth();
bool ready();
int sendReply(const MessageMutable & r);
BasicAuthCred getBasicAuthCred();
bool done = false, authorized = false;
Method method = Method::Unknown;
PIString path;
PIByteArray body;
PIMap<PIString, PIString> headers, args, post;
MHD_Connection * connection = nullptr;
MicrohttpdServer * server = nullptr;
MHD_PostProcessor * postprocessor = nullptr;
};
bool MicrohttpdServerConnection::checkBasicAuth() {
if (headers.contains(Header::Authorization)) {
auto ba_up = getBasicAuthCred();
bool ok = false; // server->callback_auth(ba_up.user, ba_up.pass);
if (server->callback_auth) ok = server->callback_auth(ba_up.user, ba_up.pass);
if (ok) {
authorized = true;
return true;
}
}
// piCout << "miss authorization";
sendReply(MessageMutable::fromCode(Code::Unauthorized)
.addHeader(Header::WWWAuthenticate, "Basic realm=\"%1\", charset=\"UTF-8\""_a.arg(server->realm))
.setBody(PIByteArray::fromAscii("Authorization required")));
// piCout << "answer sent";
return false;
}
bool MicrohttpdServerConnection::ready() {
if (!server) return false;
if (done) return true;
done = true;
MessageMutable rep;
if (method == Method::Get) {
if (path == "/favicon.ico"_a) {
// piCout << "send favicon" << server->favicon.size() << "bytes";
rep.setBody(server->favicon);
sendReply(rep);
return true;
}
}
// piCout << "ready" << (int)method << path << body.size();
MessageMutable req;
req.setMethod(method);
req.setPath(path);
req.setBody(body);
req.headers() = headers;
req.arguments() = args;
rep.setCode(Code::BadRequest);
if (server->callback) rep = server->callback(req);
MicrohttpdServer::addFixedHeaders(rep);
sendReply(rep);
// piCout << "ready ok" << (int)rep.code() << rep.body().size();
return true;
}
int MicrohttpdServerConnection::sendReply(const MessageMutable & r) {
MHD_Response * response = MHD_create_response_from_buffer(r.body().size(), (void *)r.body().data(), MHD_RESPMEM_MUST_COPY);
if (!response) {
// piCout << "null response" << r.body.size() << (void *)r.body.data();
return MHD_NO;
}
auto it = r.headers().makeIterator();
while (it.next())
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
// piCout << "status" << r.code;
int ret = MHD_queue_response(connection, static_cast<int>(r.code()), response);
MHD_destroy_response(response);
return ret;
}
BasicAuthCred MicrohttpdServerConnection::getBasicAuthCred() {
BasicAuthCred ret;
char * p = nullptr;
auto u = MHD_basic_auth_get_username_password(connection, &p);
if (u) {
ret.user = PIString::fromUTF8(u);
ret.exists = true;
MHD_free(u);
}
if (p) {
ret.pass = PIString::fromUTF8(p);
ret.exists = true;
MHD_free(p);
}
return ret;
}
void log_callback(void * cls, const char * fmt, va_list ap) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
piCout << "log" << server;
if (!server) return;
char buffer[1_KiB];
piZeroMemory(buffer, 1_KiB);
std::vsnprintf(buffer, 1_KiB, fmt, ap);
piCout << buffer;
}
int iterate_post(void * conn_cls,
MHD_ValueKind kind,
const char * key,
const char * filename,
const char * content_type,
const char * transfer_encoding,
const char * data,
uint64_t off,
size_t size) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)conn_cls;
if (!conn) return MHD_NO;
conn->post[PIString::fromUTF8(key)] = PIString::fromUTF8(data);
return MHD_YES;
}
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
// piCout << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
if (!conn) return;
if (conn->postprocessor) {
MHD_destroy_post_processor(conn->postprocessor);
conn->postprocessor = nullptr;
}
conn->ready();
piDeleteSafety(conn);
}
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->headers[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
if (!conn) return MHD_NO;
conn->args[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
return MHD_YES;
}
int answer_callback(void * cls,
MHD_Connection * connection,
const char * url,
const char * method,
const char * version,
const char * upload_data,
size_t * upload_data_size,
void ** con_cls) {
MicrohttpdServer * server = (MicrohttpdServer *)cls;
Method m = Method::Unknown;
if (0 == strcmp(method, "GET"))
m = Method::Get;
else if (0 == strcmp(method, "POST"))
m = Method::Post;
else if (0 == strcmp(method, "HEAD"))
m = Method::Head;
else if (0 == strcmp(method, "PUT"))
m = Method::Put;
else if (0 == strcmp(method, "DELETE"))
m = Method::Delete;
else if (0 == strcmp(method, "CONNECT"))
m = Method::Connect;
else if (0 == strcmp(method, "OPTIONS"))
m = Method::Options;
else if (0 == strcmp(method, "TRACE"))
m = Method::Trace;
else if (0 == strcmp(method, "PATCH"))
m = Method::Patch;
if (m == Method::Unknown) {
piCout << "[MicrohttpdServer]"
<< "Warning:"
<< "Unknown method!";
return MHD_NO;
}
// piCout << "answer" << url << method << (int)m << server;
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
if (!conn) {
conn = new MicrohttpdServerConnection();
conn->connection = connection;
conn->server = server;
conn->path = PIString::fromUTF8(url);
conn->method = m;
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
if (server->isBasicAuthEnabled() && !conn->authorized) {
if (!conn->checkBasicAuth()) return MHD_YES;
}
return MHD_YES;
}
if (m == Method::Unknown) {
return conn->sendReply(MessageMutable::fromCode(Code::MethodNotAllowed));
}
if (*upload_data_size) {
if (!conn->postprocessor) {
conn->postprocessor = MHD_create_post_processor(connection, 64_KiB, (MHD_PostDataIterator)iterate_post, (void *)conn);
}
conn->body.append(upload_data, *upload_data_size);
MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
*upload_data_size = 0;
} else {
// qDebug() << "answer ok";
if (!conn->ready()) return conn->sendReply(MessageMutable::fromCode(Code::InternalServerError));
}
return MHD_YES;
}
PRIVATE_DEFINITION_START(MicrohttpdServer)
MHD_Daemon * daemon;
PRIVATE_DEFINITION_END(MicrohttpdServer)
MicrohttpdServer::MicrohttpdServer() {
PRIVATE->daemon = nullptr;
opts[Option::ConnectionLimit] = FD_SETSIZE - 4;
opts[Option::ConnectionTimeout] = 0_s;
realm = "Restricted"_a;
}
MicrohttpdServer::~MicrohttpdServer() {
stop();
}
void MicrohttpdServer::setOption(Option o, PIVariant v) {
opts[o] = std::move(v);
}
void MicrohttpdServer::setFavicon(const PIByteArray & im) {
favicon = im;
}
bool MicrohttpdServer::listen(PINetworkAddress addr) {
stop();
uint flags = 0;
#if MHD_VERSION <= 0x00095100
flags |= MHD_USE_POLL_INTERNALLY;
#else
flags |= MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
#endif
if (opts.value(Option::HTTPSEnabled).toBool()) flags |= MHD_USE_TLS;
mem_key = opts.value(Option::HTTPSMemKey).toByteArray();
if (mem_key.isNotEmpty()) mem_key.append(0);
mem_cert = opts.value(Option::HTTPSMemCert).toByteArray();
if (mem_cert.isNotEmpty()) mem_cert.append(0);
key_pass = opts.value(Option::HTTPSKeyPassword).toByteArray();
if (key_pass.isNotEmpty()) key_pass.append(0);
sockaddr_in sa_addr;
piZeroMemory(sa_addr);
sa_addr.sin_port = htons(addr.port());
sa_addr.sin_addr.s_addr = addr.ip();
sa_addr.sin_family = AF_INET;
PIVector<MHD_OptionItem> options;
options.append({MHD_OPTION_EXTERNAL_LOGGER, (intptr_t)log_callback, this});
options.append({MHD_OPTION_NOTIFY_COMPLETED, (intptr_t)request_completed, nullptr});
options.append({MHD_OPTION_CONNECTION_LIMIT, opts.value(Option::ConnectionLimit).toInt(), nullptr});
options.append({MHD_OPTION_CONNECTION_TIMEOUT, piRound(opts.value(Option::ConnectionTimeout).toSystemTime().toSeconds()), nullptr});
options.append({MHD_OPTION_SOCK_ADDR, 0, &sa_addr});
if (opts.value(Option::HTTPSEnabled).toBool()) {
options.append({MHD_OPTION_HTTPS_MEM_KEY, 0, mem_key.data()});
options.append({MHD_OPTION_HTTPS_MEM_CERT, 0, mem_cert.data()});
options.append({MHD_OPTION_HTTPS_KEY_PASSWORD, 0, key_pass.data()});
}
options.append({MHD_OPTION_END, 0, nullptr});
PRIVATE->daemon = MHD_start_daemon(flags,
addr.port(),
nullptr,
nullptr,
(MHD_AccessHandlerCallback)answer_callback,
this,
MHD_OPTION_ARRAY,
options.data(),
MHD_OPTION_END);
return isListen();
}
bool MicrohttpdServer::isListen() const {
return PRIVATE->daemon;
}
void MicrohttpdServer::stop() {
if (PRIVATE->daemon) {
MHD_stop_daemon(PRIVATE->daemon);
PRIVATE->daemon = nullptr;
}
}
void MicrohttpdServer::addFixedHeaders(MessageMutable & msg) {
if (!msg.headers().contains(Header::ContentType)) {
if (msg.body().isNotEmpty()) {
if (msg.body().startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
msg.addHeader(Header::ContentType, "text/html; charset=utf-8");
else if (msg.body()[0] == '[' || msg.body()[0] == '{')
msg.addHeader(Header::ContentType, "application/json; charset=utf-8");
}
}
msg.addHeader(Header::AccessControlAllowOrigin, "*");
}

View File

@@ -0,0 +1,90 @@
#include "pihttpserver.h"
#include "piliterals_string.h"
PIHTTPServer::PIHTTPServer() {
setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable {
PIHTTP::MessageMutable reply;
reply.setCode(PIHTTP::Code::NotFound);
auto in_path = r.path().split("/");
in_path.removeAll("");
auto it = functions.makeReverseIterator();
bool found = false;
while (it.next()) {
if (it.value().function) {
if (it.value().method == r.method()) {
if (it.value().match(in_path)) {
reply = it.value().function(r);
found = true;
break;
}
}
}
}
if (!found && unhandled) reply = unhandled(r);
auto hit = reply_headers.makeIterator();
while (hit.next())
reply.addHeader(hit.key(), hit.value());
return reply;
});
}
PIHTTPServer::~PIHTTPServer() {
stop();
}
void PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor) {
auto & ep(functions[path + PIString::fromNumber(static_cast<int>(method))]);
ep.path = path.split("/");
ep.method = method;
ep.function = functor;
ep.path.removeAll("");
}
void PIHTTPServer::registerUnhandled(RequestFunction functor) {
unhandled = functor;
}
void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) {
auto pl = path.split("/");
pl.removeAll("");
auto it = functions.makeIterator();
while (it.next()) {
if (it.value().method == method) {
if (it.value().path == pl) {
functions.remove(it.key());
break;
}
}
}
}
void PIHTTPServer::unregisterPath(const PIString & path) {
auto pl = path.split("/");
pl.removeAll("");
auto it = functions.makeIterator();
PIStringList keys;
while (it.next()) {
if (it.value().path == pl) {
keys << it.key();
}
}
for (const auto & k: keys)
functions.remove(k);
}
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
if (in_path.size() != path.size()) return false;
for (int i = 0; i < path.size_s(); ++i) {
if (path[i] == "*"_a) continue;
if (path[i] != in_path[i]) return false;
}
return true;
}

View File

@@ -19,6 +19,8 @@
#include "pibroadcast.h" #include "pibroadcast.h"
#include "piliterals_time.h"
/** \class PIBroadcast /** \class PIBroadcast
* \brief Broadcast for all interfaces, including loopback * \brief Broadcast for all interfaces, including loopback
* *
@@ -57,8 +59,8 @@ PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
PIBroadcast::~PIBroadcast() { PIBroadcast::~PIBroadcast() {
PIThread::stop(); PIThread::stopAndWait();
mcast_mutex.unlock(); // mcast_mutex.unlock();
destroyAll(); destroyAll();
} }
@@ -84,7 +86,7 @@ void PIBroadcast::setMulticastPort(ushort port) {
} }
void PIBroadcast::setMulticastAddress(const PIEthernet::Address & addr) { void PIBroadcast::setMulticastAddress(const PINetworkAddress & addr) {
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
mcast_address = addr; mcast_address = addr;
_reinit = true; _reinit = true;
@@ -113,29 +115,28 @@ void PIBroadcast::setLoopbackPortsCount(int count) {
void PIBroadcast::destroyAll() { void PIBroadcast::destroyAll() {
piForeach (PIEthernet * e, eth_mcast) { for (auto * e: eth_mcast) {
e->stopThreadedRead(); e->stopAndWait();
delete e; piDeleteSafety(e);
} }
eth_mcast.clear(); eth_mcast.clear();
if (eth_lo) { if (eth_lo) {
eth_lo->stopThreadedRead(); eth_lo->stopAndWait();
delete eth_lo; piDeleteSafety(eth_lo);
eth_lo = 0;
} }
} }
void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) { void PIBroadcast::initAll(PIVector<PINetworkAddress> al) {
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
destroyAll(); destroyAll();
_reinit = false; _reinit = false;
prev_al = al; prev_al = al;
al.removeAll(PIEthernet::Address("127.0.0.1")); al.removeAll(PINetworkAddress("127.0.0.1"));
al << mcast_address; al << mcast_address;
eth_mcast.clear(); eth_mcast.clear();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces(); PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
piForeachC (PIEthernet::Address & a, al) { for (const auto & a: al) {
PIEthernet * ce = 0; PIEthernet * ce = 0;
// piCout << "mcast try" << a; // piCout << "mcast try" << a;
if (_channels[Multicast]) { if (_channels[Multicast]) {
@@ -166,10 +167,10 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
ce->setName("PIMulticast_" + a.toString()); ce->setName("PIMulticast_" + a.toString());
ce->setParameters(PIEthernet::Broadcast); ce->setParameters(PIEthernet::Broadcast);
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString()); const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
PIEthernet::Address nm((cint == 0) ? "255.255.255.0" : cint->netmask); PINetworkAddress nm((cint == 0) ? "255.255.255.0" : cint->netmask);
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port); ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
if (!_send_only) { if (!_send_only) {
ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port)); ce->setReadAddress(PINetworkAddress(a.ip(), bcast_port));
// piCout << "bcast " << ce->readAddress() << ce->sendAddress(); // piCout << "bcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) { if (ce->open()) {
eth_mcast << ce; eth_mcast << ce;
@@ -203,14 +204,15 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
void PIBroadcast::send(const PIByteArray & data) { void PIBroadcast::send(const PIByteArray & data) {
if (!isRunning()) { /*if (!isRunning()) {
reinit(); reinit();
PIThread::start(3000); PIThread::start(3000);
} }*/
PIByteArray cd = cryptData(data); PIByteArray cd = cryptData(data);
if (cd.isEmpty()) return; if (cd.isEmpty()) return;
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast) e->send(cd); for (auto * e: eth_mcast)
e->send(cd);
if (eth_lo) { if (eth_lo) {
for (int i = 0; i < lo_pcnt; ++i) { for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->send("127.0.0.1", lo_port + i, cd); eth_lo->send("127.0.0.1", lo_port + i, cd);
@@ -223,21 +225,23 @@ void PIBroadcast::startRead() {
if (!isRunning()) { if (!isRunning()) {
_started = false; _started = false;
reinit(); reinit();
PIThread::start(3000); PIThread::start(3_s);
} }
if (_send_only) return; if (_send_only) return;
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast) e->startThreadedRead(); for (auto * e: eth_mcast)
e->startThreadedRead();
if (eth_lo) eth_lo->startThreadedRead(); if (eth_lo) eth_lo->startThreadedRead();
_started = true; _started = true;
} }
void PIBroadcast::stopRead() { void PIBroadcast::stopRead() {
if (isRunning()) stop(); if (isRunning()) stopAndWait();
PIMutexLocker ml(mcast_mutex); PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast) e->stopThreadedRead(); for (auto * e: eth_mcast)
if (eth_lo) eth_lo->stopThreadedRead(); e->stopAndWait();
if (eth_lo) eth_lo->stopAndWait();
_started = false; _started = false;
} }
@@ -257,7 +261,7 @@ void PIBroadcast::mcastRead(const uchar * data, ssize_t size) {
void PIBroadcast::run() { void PIBroadcast::run() {
PIVector<PIEthernet::Address> al = PIEthernet::allAddresses(); PIVector<PINetworkAddress> al = PIEthernet::allAddresses();
mcast_mutex.lock(); mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al); bool r = _reinit, ac = (al != prev_al);
mcast_mutex.unlock(); mcast_mutex.unlock();

View File

@@ -18,6 +18,8 @@
*/ */
#include "piethutilbase.h" #include "piethutilbase.h"
#include "pitranslator.h"
#ifdef PIP_CRYPT #ifdef PIP_CRYPT
# include "picrypt.h" # include "picrypt.h"
#endif #endif
@@ -51,8 +53,7 @@ PIEthUtilBase::PIEthUtilBase() {
} }
PIEthUtilBase::~PIEthUtilBase() { PIEthUtilBase::~PIEthUtilBase() {}
}
void PIEthUtilBase::setCryptEnabled(bool on) { void PIEthUtilBase::setCryptEnabled(bool on) {
@@ -86,7 +87,8 @@ void PIEthUtilBase::createCryptKey(const PIString & k) {
_key = PICrypt::hash("sodium_bug"); _key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash(k); _key = PICrypt::hash(k);
#else #else
piCout << "[PIEthUtilBase] PICrypt wasn`t built!"; piCout << "[PIEthUtilBase]"
<< "PICrypt wasn`t built!"_tr("PIEthUtilBase");
#endif #endif
_crypt = true; _crypt = true;
} }
@@ -119,3 +121,11 @@ PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
return PIByteArray(); return PIByteArray();
#endif #endif
} }
size_t PIEthUtilBase::cryptSizeAddition() {
#ifdef PIP_CRYPT
return PICrypt::sizeCrypt();
#else
return 0;
#endif
}

View File

@@ -0,0 +1,199 @@
/*
PIP - Platform Independent Primitives
PIPackedTCP
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pipackedtcp.h"
#include "piethernet.h"
#include "piliterals.h"
/** \class PIPackedTCP pipackedtcp.h
* \brief
* TCP packed channel
*
* \details
* \section PITCP_sec0 Synopsis
* %PIEthernet designed to work with IPv4 network via two protocols:
* UDP and TCP. This class allow you send and receive packets to/from
* another computer through network. Also it supports broadcast and
* multicast extensions.
*
* */
PIPackedTCP::PIPackedTCP(Role role, const PINetworkAddress & addr): m_role(role) {
setMode(PIIODevice::ReadWrite);
packer.setCryptEnabled(false);
CONNECTL(&packer, packetReceiveEvent, [this](PIByteArray & data) {
PIMutexLocker ml(rec_mutex);
rec_queue.enqueue(data);
});
init();
setAddress(addr);
}
PIPackedTCP::~PIPackedTCP() {
stopAndWait();
if (client) client->stopAndWait();
if (eth) eth->stopAndWait();
piDeleteSafety(eth);
}
void PIPackedTCP::setAddress(const PINetworkAddress & addr) {
m_addr = addr;
setPath(m_addr.toString());
}
bool PIPackedTCP::isConnected() const {
if (m_role == Client) {
return eth->isConnected();
} else {
if (client) return client->isConnected();
}
return false;
}
bool PIPackedTCP::isConnecting() const {
if (m_role == Client) {
return eth->isConnecting();
} else {
if (client) return client->isConnecting();
}
return false;
}
void PIPackedTCP::init() {
if (client) client->stopAndWait();
if (eth) eth->stopAndWait();
piDeleteSafety(eth);
eth = new PIEthernet(m_role == Client ? PIEthernet::TCP_Client : PIEthernet::TCP_Server);
if (m_role == Client) {
eth->setReopenTimeout(100_ms);
packer.assignDevice(eth);
CONNECTL(eth, connected, [this]() {
packer.clear();
connected();
});
CONNECTL(eth, disconnected, [this](bool) {
packer.clear();
eth->connect(path(), true);
disconnected();
});
} else {
CONNECTL(eth, newConnection, [this](PIEthernet * c) {
if (client) client->stopAndWait();
piDeleteSafety(client);
client = c;
// piCout << "Server connected" << client;
packer.assignDevice(client);
CONNECTL(client, disconnected, [this](bool) {
// packer.assignDevice(nullptr); WTF?
packer.clear();
disconnected();
});
client->startThreadedRead();
connected();
});
}
}
PIIODevice::DeviceInfoFlags PIPackedTCP::deviceInfoFlags() const {
return PIIODevice::Reliable;
}
PIString PIPackedTCP::constructFullPathDevice() const {
return PIString(m_role == Client ? "client" : "server") + ":" + path();
}
void PIPackedTCP::configureFromFullPathDevice(const PIString & full_path) {
PIStringList pl = full_path.split(":");
if (pl.size() >= 1) {
PIString p = pl[0].toLowerCase().left(1);
if (p == "c") m_role = Client;
if (p == "s") m_role = Server;
init();
}
PINetworkAddress addr("0.0.0.0", 13362);
if (pl.size() >= 2) {
if (pl[1].isNotEmpty()) addr.setIP(pl[1]);
}
if (pl.size() >= 3) {
if (pl[2].isNotEmpty()) addr.setPort(pl[2].toInt());
}
setAddress(addr);
}
ssize_t PIPackedTCP::readDevice(void * read_to, ssize_t max_size) {
PIMutexLocker ml(rec_mutex);
if (rec_queue.isNotEmpty()) {
auto d = rec_queue.dequeue();
auto sz = piMin(max_size, d.size_s());
if (read_to) memcpy(read_to, d.data(), sz);
return sz;
}
return 0;
}
ssize_t PIPackedTCP::writeDevice(const void * data, ssize_t max_size) {
if (!isConnected()) return 0;
packer.send(PIByteArray(data, max_size));
// piCout << m_role << "write" << eth;
return max_size;
/*if (m_role == Client) {
return eth->write(data, max_size);
} else {
if (client) return client->write(data, max_size);
}*/
}
bool PIPackedTCP::openDevice() {
if (m_role == Client) {
if (eth->isConnected()) return true;
if (eth->isConnecting()) return false;
packer.clear();
bool ret = eth->connect(path(), false);
eth->startThreadedRead();
return ret;
} else {
return eth->listen(path(), false);
}
return false;
}
bool PIPackedTCP::closeDevice() {
if (client) {
client->close();
client->stopAndWait();
piDeleteSafety(client);
// packer.assignDevice(nullptr); WTF?
}
return eth->close();
}

View File

@@ -22,7 +22,9 @@
# pragma GCC diagnostic ignored "-Wnonnull" # pragma GCC diagnostic ignored "-Wnonnull"
#endif #endif
#include "pistreampacker.h" #include "pistreampacker.h"
#include "piiodevice.h" #include "piiodevice.h"
#include "pitranslator.h"
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
@@ -47,27 +49,10 @@
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() { PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
crypt_frag = crypt_size = false;
aggressive_optimization = true;
packet_size = -1; packet_size = -1;
size_crypted_size = sizeof(int); if (dev) assignDevice(dev);
crypt_frag_size = 1024*1024;
max_packet_size = 1400;
packet_sign = 0xAFBE;
assignDevice(dev);
} }
void PIStreamPacker::setCryptSizeEnabled(bool on) {
crypt_size = on;
if (crypt_size) {
PIByteArray ba; ba << int(0);
size_crypted_size = cryptData(ba).size_s();
} else
size_crypted_size = sizeof(int);
}
void PIStreamPacker::clear() { void PIStreamPacker::clear() {
packet.clear(); packet.clear();
packet_size = -1; packet_size = -1;
@@ -77,33 +62,23 @@ void PIStreamPacker::clear() {
void PIStreamPacker::send(const PIByteArray & data) { void PIStreamPacker::send(const PIByteArray & data) {
if (data.isEmpty()) return; if (data.isEmpty()) return;
PIByteArray cd; PIByteArray cd = cryptData(data);
if (crypt_frag) {
int fcnt = (data.size_s() - 1) / crypt_frag_size + 1, fst = 0;
//piCout << "crypt_frag send" << fcnt << "frags";
PIByteArray frag;
for (int i = 0; i < fcnt; ++i) {
if (i == fcnt - 1) frag = PIByteArray(data.data(fst), data.size_s() - fst);
else frag = PIByteArray(data.data(fst), crypt_frag_size);
fst += crypt_frag_size;
cd << cryptData(frag);
}
} else {
cd = cryptData(data);
}
// piCout << "crypt" << data.size() << "->" << cd.size() << key().size(); // piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
PIByteArray hdr, part; PIByteArray hdr, part;
hdr << packet_sign; hdr << packet_sign;
if (crypt_size) { if (crypt_size) {
PIByteArray crsz; crsz << int(cd.size_s()); PIByteArray crsz;
crsz << int(cd.size_s());
hdr.append(cryptData(crsz)); hdr.append(cryptData(crsz));
} else } else
hdr << int(cd.size_s()); hdr << int(cd.size_s());
cd.insert(0, hdr); cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0; int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
for (int i = 0; i < pcnt; ++i) { for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst); if (i == pcnt - 1)
else part = PIByteArray(cd.data(pst), max_packet_size); part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else
part = PIByteArray(cd.data(pst), max_packet_size);
// piCout << "send" << part.size(); // piCout << "send" << part.size();
sendRequest(part); sendRequest(part);
pst += max_packet_size; pst += max_packet_size;
@@ -112,6 +87,7 @@ void PIStreamPacker::send(const PIByteArray & data) {
void PIStreamPacker::received(const uchar * readed, ssize_t size) { void PIStreamPacker::received(const uchar * readed, ssize_t size) {
if (size <= 0) return;
received(PIByteArray(readed, size)); received(PIByteArray(readed, size));
} }
@@ -120,33 +96,39 @@ void PIStreamPacker::received(const PIByteArray & data) {
stream.append(data); stream.append(data);
// piCout << "rec" << data.size(); // piCout << "rec" << data.size();
while (!stream.isEmpty()) { while (!stream.isEmpty()) {
int hdr_size = sizeof(packet_sign) + size_crypted_size; int hdr_size = sizeof(packet_sign) + sizeCryptedSize();
if (packet_size < 0) { if (packet_size < 0) {
if (stream.size_s() < hdr_size) return; if (stream.size_s() < hdr_size) return;
ushort sign(0); ushort sign(0);
memcpy(&sign, stream.data(), 2); memcpy(&sign, stream.data(), 2);
if (sign != packet_sign) { if (sign != packet_sign) {
if (aggressive_optimization) stream.clear(); if (aggressive_optimization)
else stream.pop_front(); stream.clear();
else
stream.pop_front();
continue; continue;
} }
int sz = -1; int sz = -1;
if (crypt_size) { if (crypt_size) {
PIByteArray crsz((uint)size_crypted_size); PIByteArray crsz(sizeCryptedSize());
memcpy(crsz.data(), stream.data(2), size_crypted_size); memcpy(crsz.data(), stream.data(2), crsz.size());
crsz = decryptData(crsz); crsz = decryptData(crsz);
if (crsz.size() < sizeof(sz)) { if (crsz.size() < sizeof(sz)) {
if (aggressive_optimization) stream.clear(); if (aggressive_optimization)
else stream.pop_front(); stream.clear();
else
stream.pop_front();
continue; continue;
} }
crsz >> sz; crsz >> sz;
} else { } else {
memcpy(&sz, stream.data(2), size_crypted_size); memcpy(&sz, stream.data(2), sizeCryptedSize());
} }
if (sz < 0) { if (sz < 0) {
if (aggressive_optimization) stream.clear(); if (aggressive_optimization)
else stream.pop_front(); stream.clear();
else
stream.pop_front();
continue; continue;
} }
stream.remove(0, hdr_size); stream.remove(0, hdr_size);
@@ -154,34 +136,18 @@ void PIStreamPacker::received(const PIByteArray & data) {
packet_size = sz; packet_size = sz;
if (packet_size == 0) if (packet_size == 0)
packet_size = -1; packet_size = -1;
else
startPacketReceive(packet_size);
continue; continue;
} else { } else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s()); int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps); packet.append(stream.data(), ps);
stream.remove(0, ps); stream.remove(0, ps);
if (packet.size_s() == packet_size) { if (packet.size_s() == packet_size) {
PIByteArray cd; PIByteArray cd = decryptData(packet);
if (crypt_frag) {
//piCout << "decrypt frags ..." << packet_size;
while (packet.size_s() >= 4) {
//piCout << "decrypt frags take data ...";
PIByteArray frag;
//piCout << "decrypt frags take data done" << frag.size_s();
packet >> frag;
if (frag.isEmpty()) {
//piCout << "decrypt frags corrupt, break";
cd.clear();
break;
}
cd.append(decryptData(frag));
//piCout << "decrypt frags add" << frag.size_s();
}
//piCout << "decrypt frags done" << cd.size();
} else {
cd = decryptData(packet);
}
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size(); // piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
if (!cd.isEmpty()) { if (!cd.isEmpty()) {
endPacketReceive();
packetReceived(cd); packetReceived(cd);
packetReceiveEvent(cd); packetReceiveEvent(cd);
} }
@@ -194,10 +160,17 @@ void PIStreamPacker::received(const PIByteArray & data) {
void PIStreamPacker::assignDevice(PIIODevice * dev) { void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) return; if (!dev) {
piCoutObj << "Error! device is NULL";
return;
}
if (!dev->infoFlags()[PIIODevice::Reliable]) { if (!dev->infoFlags()[PIIODevice::Reliable]) {
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev; piCoutObj << "Warning! Not recommended to use with non-reliable device"_tr("PIStreamPacker") << dev;
} }
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received); CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
CONNECT1(void, PIByteArray, this, sendRequest, dev, write); CONNECT1(void, PIByteArray, this, sendRequest, dev, write);
} }
uint PIStreamPacker::sizeCryptedSize() {
return sizeof(int) + (crypt_size ? cryptSizeAddition() : 0);
}

View File

@@ -50,4 +50,3 @@ luabridge::LuaRef PILuaProgram::getGlobal(const PIString & name) {
luabridge::Namespace PILuaProgram::getGlobalNamespace() { luabridge::Namespace PILuaProgram::getGlobalNamespace() {
return luabridge::getGlobalNamespace(PRIVATE->lua_state); return luabridge::getGlobalNamespace(PRIVATE->lua_state);
} }

View File

@@ -0,0 +1,60 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \defgroup Application Application
//! \~\brief
//! \~english Application-level classes.
//! \~russian Классы уровня "приложение".
//!
//! \~\details
//! \~english \section cmake_module_Application Building with CMake
//! \~russian \section cmake_module_Application Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides some classes for help to create application
//!
//! \~russian
//! Эти файлы предоставляют классы для облегчения создания приложения
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PIAPPLICATIONMODULE_H
#define PIAPPLICATIONMODULE_H
#include "picli.h"
#include "pilog.h"
#include "pisingleapplication.h"
#include "pisystemmonitor.h"
#include "pitranslator.h"
#endif

View File

@@ -0,0 +1,256 @@
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "picli.h"
#include "pisysteminfo.h"
#include "pitranslator.h"
//! \class PICLI picli.h
//! \details
//! \~english \section PICLI_sec0 Synopsis
//! \~russian \section PICLI_sec0 Краткий обзор
//! \~english
//! This class provide handy parsing of command-line arguments. First you should add
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
//! is some argument in application command-line with function \a hasArgument(),
//! or obtain argument value by \a argumentValue().
//!
//! \~russian
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
//! а также получать их значения при помощи \a argumentValue().
//!
//! \~english \section PICLI_sec1 Example
//! \~russian \section PICLI_sec1 Пример
//! \~\code
//! int main(int argc, char ** argv) {
//! PICLI cli(argc, argv);
//! cli.addArgument("console");
//! cli.addArgument("debug");
//! cli.addArgument("Value", "v", "value", true);
//! if (cli.hasArgument("console"))
//! piCout << "console active";
//! if (cli.hasArgument("debug"))
//! piCout << "debug active";
//! piCout << "Value =" << cli.argumentValue("Value");
//! return 0;
//! }
//! \endcode
//!
//! \~english These executions are similar:
//! \~russian Эти вызовы будут идентичны:
//!
//! \~\code
//! a.out -cd -v 10
//! a.out --value 10 -dc
//! a.out -c -v 10 -d
//! a.out --console -d -v 10
//! a.out --debug -c --value 10
//! \endcode
//!
PICLI::PICLI(int argc, char * argv[]) {
for (int i = 0; i < argc; ++i)
_args_raw << argv[i];
if (argc > 0) PISystemInfo::instance()->execCommand = argv[0];
}
void PICLI::parse() {
if (!needParse) return;
PIString cra, full;
Argument * last = 0;
for (int i = 1; i < _args_raw.size_s(); ++i) {
cra = _args_raw[i];
if (cra.left(2) == _prefix_full) {
last = 0;
full = cra.right(cra.length() - 2);
for (auto & a: _args) {
if (a.full_key == full) {
a.found = true;
last = &a;
break;
}
}
} else {
if (cra.left(1) == _prefix_short) {
last = 0;
for (int j = 1; j < cra.length(); ++j) {
bool found = false;
for (auto & a: _args) {
if ((a.short_key != '\0') && (a.short_key == cra[j])) {
a.found = true;
last = &a;
found = true;
break;
}
}
if (!found) break;
}
} else {
if (last == 0 ? true : !last->has_value) {
if (_args_mand.size_s() < _count_mand) {
_args_mand << cra;
continue;
}
if (_args_opt.size_s() < _count_opt || _count_opt < 0) {
_args_opt << cra;
continue;
}
piCoutObj << "Arguments overflow, \"%1\" ignored"_tr("PICLI").arg(cra);
}
if (last == 0 ? false : last->has_value) {
last->value = cra;
last = 0;
}
}
}
}
needParse = false;
}
void PICLI::addArgument(const PIString & name, bool value) {
_args << Argument(name, name[0], name, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const PIChar & shortKey, bool value) {
_args << Argument(name, shortKey, name, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const char * shortKey, bool value) {
_args << Argument(name, PIChar::fromUTF8(shortKey), name, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value) {
_args << Argument(name, shortKey, fullKey, value);
needParse = true;
}
void PICLI::addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value) {
_args << Argument(name, PIChar::fromUTF8(shortKey), fullKey, value);
needParse = true;
}
PIString PICLI::rawArgument(int index) {
parse();
return _args_raw[index];
}
PIString PICLI::mandatoryArgument(int index) {
parse();
return _args_mand[index];
}
PIString PICLI::optionalArgument(int index) {
parse();
return _args_opt[index];
}
const PIStringList & PICLI::rawArguments() {
parse();
return _args_raw;
}
const PIStringList & PICLI::mandatoryArguments() {
parse();
return _args_mand;
}
const PIStringList & PICLI::optionalArguments() {
parse();
return _args_opt;
}
PIString PICLI::programCommand() {
parse();
return _args_raw.isNotEmpty() ? _args_raw.front() : PIString();
}
bool PICLI::hasArgument(const PIString & name) {
parse();
for (const auto & i: _args)
if (i.name == name && i.found) return true;
return false;
}
PIString PICLI::argumentValue(const PIString & name) {
parse();
for (const auto & i: _args)
if (i.name == name && i.found) return i.value;
return PIString();
}
PIString PICLI::argumentShortKey(const PIString & name) {
for (const auto & i: _args)
if (i.name == name) return PIString(i.short_key);
return PIString();
}
PIString PICLI::argumentFullKey(const PIString & name) {
for (const auto & i: _args)
if (i.name == name) return i.full_key;
return PIString();
}
void PICLI::setShortKeyPrefix(const PIString & prefix) {
_prefix_short = prefix;
needParse = true;
}
void PICLI::setFullKeyPrefix(const PIString & prefix) {
_prefix_full = prefix;
needParse = true;
}
void PICLI::setMandatoryArgumentsCount(const int count) {
_count_mand = count;
needParse = true;
}
void PICLI::setOptionalArgumentsCount(const int count) {
_count_opt = count;
needParse = true;
}

View File

@@ -0,0 +1,136 @@
/*! \file picli.h
* \ingroup Application
* \~\brief
* \~english Command-Line parser
* \~russian Парсер командной строки
*/
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICLI_H
#define PICLI_H
#include "piset.h"
#include "pistringlist.h"
//! \ingroup Application
//! \~\brief
//! \~english Command-Line parser.
//! \~russian Парсер командной строки.
class PIP_EXPORT PICLI {
public:
//! \~english Constructs %PICLI from "argc" and "argv" from "int main()" method.
//! \~russian Создает %PICLI из "argc" и "argv" из метода "int main()".
PICLI(int argc, char * argv[]);
//! \~english Add argument with name "name", short key = name first letter and full key = name.
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени.
void addArgument(const PIString & name, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = name.
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени.
void addArgument(const PIString & name, const char * shortKey, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false);
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey".
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey".
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false);
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command.
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы.
PIString rawArgument(int index);
PIString mandatoryArgument(int index);
PIString optionalArgument(int index);
//! \~english Returns unparsed command-line arguments.
//! \~russian Возвращает исходные аргументы командной строки.
const PIStringList & rawArguments();
const PIStringList & mandatoryArguments();
const PIStringList & optionalArguments();
//! \~english Returns program execute command without arguments.
//! \~russian Возвращает команду вызова программы без аргументов.
PIString programCommand();
//! \~english Returns if argument "name" found.
//! \~russian Возвращает найден ли аргумент "name".
bool hasArgument(const PIString & name);
//! \~english Returns argument "name" value, or empty string if this is no value.
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет.
PIString argumentValue(const PIString & name);
//! \~english Returns short key of argument "name", or empty string if this is no argument.
//! \~russian Возвращает короткий ключ аргумента "name" или пустую строку, если аргумента нет.
PIString argumentShortKey(const PIString & name);
//! \~english Returns full key of argument "name", or empty string if this is no argument.
//! \~russian Возвращает полный ключ аргумента "name" или пустую строку, если аргумента нет.
PIString argumentFullKey(const PIString & name);
const PIString & shortKeyPrefix() const { return _prefix_short; }
const PIString & fullKeyPrefix() const { return _prefix_full; }
int mandatoryArgumentsCount() const { return _count_mand; }
int optionalArgumentsCount() const { return _count_opt; }
void setShortKeyPrefix(const PIString & prefix);
void setFullKeyPrefix(const PIString & prefix);
void setMandatoryArgumentsCount(const int count);
void setOptionalArgumentsCount(const int count);
bool debug() const { return debug_; }
void setDebug(bool debug) { debug_ = debug; }
PIConstChars className() const { return "PICLI"; }
PIString name() const { return PIStringAscii("CLI"); }
private:
struct Argument {
Argument() {}
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {
name = n;
short_key = s;
full_key = f;
has_value = v;
}
PIString name;
PIChar short_key;
PIString full_key;
PIString value;
bool has_value = false, found = false;
};
void parse();
PIString _prefix_short = "-", _prefix_full = "--";
PIStringList _args_raw, _args_mand, _args_opt;
PISet<PIString> keys_full, keys_short;
PIVector<Argument> _args;
int _count_mand = 0, _count_opt = 0;
bool needParse = true, debug_ = true;
};
#endif // PICLI_H

View File

@@ -0,0 +1,247 @@
/*
PIP - Platform Independent Primitives
High-level log
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pilog.h"
#include "pidir.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include "pitime.h"
//! \class PILog pilog.h
//! \details
//! \~english \section PILog_sec0 Synopsis
//! \~russian \section PILog_sec0 Краткий обзор
//! \~english
//! This class provides log with optional file and console output.
//!
//! \~russian
//! Этот класс предоставляет лог с опциональным выводом в файл и консоль.
//!
PILog::PILog(): PIThread(), log_ts(&log_file) {
setName("PILog");
split_time = 8_h;
timestamp_format = "yyyy-MM-dd hh:mm:ss.zzz";
setLineFormat("t - c: m");
id_by_cat[Level::Info] = PICout::registerExternalBufferID();
id_by_cat[Level::Debug] = PICout::registerExternalBufferID();
id_by_cat[Level::Warning] = PICout::registerExternalBufferID();
id_by_cat[Level::Error] = PICout::registerExternalBufferID();
CONNECTU(PICout::Notifier::object(), finished, this, coutDone);
}
PILog::~PILog() {
stop();
}
void PILog::setDir(const PIString & d) {
stopAndWait();
log_dir = d;
if (output[File]) {
PIDir::make(log_dir);
newFile();
}
start();
}
void PILog::setLineFormat(const PIString & f) {
line_format = f;
line_format_p = line_format;
line_format_p.replace("t", "${t}").replace("c", "${c}").replace("m", "${m}");
}
void PILog::setLevel(Level l) {
max_level = l;
}
PICout PILog::error(PIObject * context) {
return makePICout(context, Level::Error);
}
PICout PILog::warning(PIObject * context) {
return makePICout(context, Level::Warning);
}
PICout PILog::info(PIObject * context) {
return makePICout(context, Level::Info);
}
PICout PILog::debug(PIObject * context) {
return makePICout(context, Level::Debug);
}
void PILog::stop() {
while (true) {
log_mutex.lock();
bool done = queue.isEmpty();
log_mutex.unlock();
if (done) break;
piMinSleep();
}
PIThread::stopAndWait();
}
PIStringList PILog::readAllLogs() const {
PIMap<PISystemTime, PIString> names;
auto dir = PIDir(log_dir);
auto fil = dir.entries();
for (auto fi: fil) {
if (!fi.isFile()) continue;
if (!fi.name().contains(".log.")) continue;
names[PIDateTime::current().fromString(fi.baseName(), "yyyy_MM_dd__hh_mm_ss").toSystemTime()] = dir.relative(fi.path);
}
PIStringList ret;
PIString cur_filename = dir.relative(log_file.path());
auto it = names.makeIterator();
bool was_own = false;
auto readFile = [&ret](PIFile * f) {
PIIOTextStream ts(f);
PIString line;
while (!ts.isEnd()) {
line = ts.readLine().trim();
if (line.isNotEmpty()) ret << line;
}
};
while (it.next()) {
PIFile * f = nullptr;
bool own = true;
if (it.value() == cur_filename) {
log_mutex.lock();
f = &log_file;
f->seekToBegin();
own = false;
was_own = true;
} else {
f = new PIFile(log_dir + "/" + it.value(), PIIODevice::ReadOnly);
}
readFile(f);
if (own)
delete f;
else {
f->seekToEnd();
log_mutex.unlock();
}
}
if (!was_own) {
log_mutex.lock();
log_file.seekToBegin();
readFile(&log_file);
log_file.seekToEnd();
log_mutex.unlock();
}
return ret;
}
void PILog::coutDone(int id, PIString * buffer) {
if (!buffer) return;
if (!id_by_cat.containsValue(id)) return;
auto cat = id_by_cat.key(id, PILog::Level::Debug);
if (cat > max_level) return;
enqueue(*buffer, cat);
delete buffer;
}
PICout PILog::makePICout(PIObject * context, Level cat) {
auto buffer = new PIString();
if (context) {
*buffer = "["_a + context->className();
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
*buffer += "] ";
}
return PICout::withExternalBufferAndID(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
}
void PILog::enqueue(const PIString & msg, Level cat) {
auto t = PIDateTime::fromSystemTime(PISystemTime::current());
PIMutexLocker ml(log_mutex);
queue.enqueue({cat, t, msg});
}
PIString PILog::entryToString(const Entry & e) const {
static PIStringList categories{"error", "warn ", "info ", "debug"};
PIString t = e.time.toString(timestamp_format);
PIString ret = line_format_p;
ret.replace("${t}", t).replace("${c}", categories[static_cast<int>(e.cat)]).replace("${m}", e.msg);
return ret;
}
void PILog::newFile() {
PIString aname = log_name;
if (aname.isNotEmpty()) aname += "__";
log_file.open(log_dir + "/" + aname + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss") + ".log." +
PIString::fromNumber(++part_number),
PIIODevice::ReadWrite);
}
void PILog::run() {
if (output[File]) {
if (split_tm.elapsed() >= split_time) {
split_tm.reset();
newFile();
}
}
log_mutex.lock();
if (queue.isEmpty()) {
log_mutex.unlock();
piMSleep(20);
return;
}
log_mutex.unlock();
while (true) {
log_mutex.lock();
if (queue.isEmpty()) {
log_mutex.unlock();
return;
}
auto qi = queue.dequeue();
log_mutex.unlock();
auto str = entryToString(qi);
if (log_file.isOpened()) log_ts << str << "\n";
if (output[Console]) {
PICout out(qi.cat == Level::Error ? piCerr : piCout);
if (color_console) {
switch (qi.cat) {
case Level::Error: out << PICoutManipulators::Red; break;
case Level::Warning: out << PICoutManipulators::Yellow; break;
default: break;
}
}
out << str;
}
}
}

View File

@@ -0,0 +1,181 @@
/*! \file pilog.h
* \ingroup Application
* \~\brief
* \~english High-level log
* \~russian Высокоуровневый лог
*/
/*
PIP - Platform Independent Primitives
High-level log
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIlog_H
#define PIlog_H
#include "pifile.h"
#include "piiostream.h"
#include "pithread.h"
//! \ingroup Application
//! \~\brief
//! \~english High-level log
//! \~russian Высокоуровневый лог
class PIP_EXPORT PILog: public PIThread {
PIOBJECT_SUBCLASS(PILog, PIThread)
public:
PILog();
~PILog();
//! \~english Message category
//! \~russian Категория сообщения
enum class Level {
Error /** \~english Error \~russian Ошибка */,
Warning /** \~english Warning \~russian Предупреждение */,
Info /** \~english Information \~russian Информация */,
Debug /** \~english Debug \~russian Отладка */,
};
//! \~english Output channel
//! \~russian Канал вывода
enum Output {
File /** \~english File \~russian Файл */ = 0x1,
Console /** \~english Console \~russian Консоль */ = 0x2,
All /** \~english All \~russian Все */ = 0xFF,
};
//! \~english Set output channel \"o\" to \"on\".
//! \~russian Установить канал вывода \"o\" в \"on\".
void setOutput(Output o, bool on = true) { output.setFlag(o, on); }
//! \~english Returns prefix for filename.
//! \~russian Возвращает префикс имени файла.
PIString logName() const { return log_name; }
//! \~english Set prefix for filename. Should be set \b before \a setDir()!
//! \~russian Устанавливает префикс имени файла. Должен быть установлен \b до вызова \a setDir()!
void setLogName(const PIString & n) { log_name = n; }
//! \~english Returns if color for console output enabled.
//! \~russian Возвращает использовать ли цвет для вывода в консоль.
bool colorConsole() const { return color_console; }
//! \~english Set color for console output enabled. True by default.
//! \~russian Устанавливает использовать ли цвет для вывода в консоль. Включено по умолчанию.
void setColorConsole(bool yes) { color_console = yes; }
//! \~english Returns directory for log files.
//! \~russian Возвращает директорию для файлов.
PIString dir() const { return log_dir; }
//! \~english Set directory for log files. Should be set \b after \a setLogName()!
//! \~russian Устанавливает директорию для файлов. Должна быть установлена \b после вызова \a setLogName()!
void setDir(const PIString & d);
//! \~english Returns lifetime for file.
//! \~russian Возвращает время жизни файла.
PISystemTime fileSplitTime() const { return split_time; }
//! \~english Set lifetime for file. Each "st" interval new file will be created.
//! \~russian Устанавливает время жизни файла. Каждый интервал "st" будет создан новый файл.
void setFileSplitTime(PISystemTime st) { split_time = st; }
//! \~english Returns timestamp format for line.
//! \~russian Возвращает формат метки времени для строки.
PIString timestampFormat() const { return timestamp_format; }
//! \~english Set timestamp format for line. Default is "yyyy-MM-dd hh:mm:ss.zzz".
//! \~russian Устанавливает формат метки времени для строки. По умолчанию "yyyy-MM-dd hh:mm:ss.zzz".
void setTimestampFormat(const PIString & f) { timestamp_format = f; }
//! \~english Returns line format.
//! \~russian Возвращает формат строки.
PIString lineFormat() const { return line_format; }
//! \~english Set line format. "t" is timestamp, "c" is category and "m" is message. Default is "t - c: m".
//! \~russian Устанавливает формат строки. "t" - метка времени, "c" - категория и "m" - сообщение. По умолчанию "t - c: m".
void setLineFormat(const PIString & f);
//! \~english Returns maximum level.
//! \~russian Возвращает максимальную категорию.
Level level() const { return max_level; }
//! \~english Set maximum level. All levels greater than \"l\" will be ignored. Default is \a Level::Debug.
//! \~russian Устанавливает максимальную категорию. Все сообщения с большей категорией, чем \"l\", будут игнорироваться. По умолчанию \a
//! Level::Debug.
void setLevel(Level l);
//! \~english Returns \a PICout for \a Level::Error level.
//! \~russian Возвращает \a PICout для категории \a Level::Error.
PICout error(PIObject * context = nullptr);
//! \~english Returns \a PICout for \a Level::Warning level.
//! \~russian Возвращает \a PICout для категории \a Level::Warning.
PICout warning(PIObject * context = nullptr);
//! \~english Returns \a PICout for \a Level::Info level.
//! \~russian Возвращает \a PICout для категории \a Level::Info.
PICout info(PIObject * context = nullptr);
//! \~english Returns \a PICout for \a Level::Debug level.
//! \~russian Возвращает \a PICout для категории \a Level::Debug.
PICout debug(PIObject * context = nullptr);
//! \~english Write all queued lines and stop. Also called in destructor.
//! \~russian Записывает все строки из очереди и останавливается. Также вызывается в деструкторе.
void stop();
//! \~english Read all previous and current log content and returns them as %PIStringList.
//! \~russian Читает все предыдущие и текущий логи и возвращает их как %PIStringList.
PIStringList readAllLogs() const;
private:
EVENT_HANDLER2(void, coutDone, int, id, PIString *, buff);
PICout makePICout(PIObject * context, Level cat);
void enqueue(const PIString & msg, Level cat = Level::Debug);
struct Entry {
Level cat;
PIDateTime time;
PIString msg;
};
PIString entryToString(const Entry & e) const;
void newFile();
void run() override;
mutable PIMutex log_mutex;
mutable PIFile log_file;
PIIOTextStream log_ts;
PITimeMeasurer split_tm;
PISystemTime split_time;
PIString log_dir, timestamp_format, line_format, line_format_p, log_name;
PIQueue<Entry> queue;
PIMap<Level, int> id_by_cat;
Level max_level = Level::Debug;
PIFlags<Output> output = All;
bool color_console = true;
int part_number = -1, cout_id = -1;
};
#endif

View File

@@ -18,7 +18,11 @@
*/ */
#include "pisingleapplication.h" #include "pisingleapplication.h"
#include "piliterals_bytes.h"
#include "piliterals_time.h"
#include "pisharedmemory.h" #include "pisharedmemory.h"
#include "pitime.h"
//! \class PISingleApplication pisingleapplication.h //! \class PISingleApplication pisingleapplication.h
@@ -60,7 +64,7 @@
//! //!
#define SHM_SIZE 1024*32 #define SHM_SIZE 32_KiB
PISingleApplication::PISingleApplication(const PIString & app_name): PIThread() { PISingleApplication::PISingleApplication(const PIString & app_name): PIThread() {
@@ -68,14 +72,13 @@ PISingleApplication::PISingleApplication(const PIString & app_name): PIThread()
started = false; started = false;
sacnt = 0; sacnt = 0;
shm = new PISharedMemory("sa_" + app_name, SHM_SIZE); shm = new PISharedMemory("sa_" + app_name, SHM_SIZE);
start(100); start(10_Hz);
} }
PISingleApplication::~PISingleApplication() { PISingleApplication::~PISingleApplication() {
stop(); stop();
if (!waitForFinish(5000)) if (!waitForFinish(5_s)) terminate();
terminate();
delete shm; delete shm;
} }
@@ -133,7 +136,7 @@ void PISingleApplication::run() {
shm->read(readed.data(), readed.size(), hdr_sz); shm->read(readed.data(), readed.size(), hdr_sz);
PIByteArray msg; PIByteArray msg;
readed >> msg; readed >> msg;
if (!msg.isEmpty()) { if (msg.isNotEmpty()) {
messageReceived(msg); messageReceived(msg);
// piCoutObj << "message" << msg; // piCoutObj << "message" << msg;
} }

View File

@@ -1,5 +1,5 @@
/*! \file pisingleapplication.h /*! \file pisingleapplication.h
* \ingroup System * \ingroup Application
* \~\brief * \~\brief
* \~english Single-instance application control * \~english Single-instance application control
* \~russian Контроль одного экземпляра приложения * \~russian Контроль одного экземпляра приложения
@@ -30,14 +30,14 @@
class PISharedMemory; class PISharedMemory;
//! \ingroup System //! \ingroup Application
//! \~\brief //! \~\brief
//! \~english Single-instance application control. //! \~english Single-instance application control.
//! \~russian Контроль одного экземпляра приложения. //! \~russian Контроль одного экземпляра приложения.
class PIP_EXPORT PISingleApplication: public PIThread { class PIP_EXPORT PISingleApplication: public PIThread {
PIOBJECT_SUBCLASS(PISingleApplication, PIThread); PIOBJECT_SUBCLASS(PISingleApplication, PIThread);
public:
public:
//! \~english Construct %PISingleApplication with name "app_name" //! \~english Construct %PISingleApplication with name "app_name"
//! \~russian Создает %PISingleApplication с именем "app_name" //! \~russian Создает %PISingleApplication с именем "app_name"
PISingleApplication(const PIString & app_name = PIString()); PISingleApplication(const PIString & app_name = PIString());
@@ -81,7 +81,6 @@ private:
PIByteArray readed; PIByteArray readed;
bool first, started; bool first, started;
int sacnt; int sacnt;
}; };
#endif // PISINGLEAPPLICATION_H #endif // PISINGLEAPPLICATION_H

View File

@@ -17,12 +17,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piincludes_p.h"
#include "pisystemmonitor.h" #include "pisystemmonitor.h"
#include "pisysteminfo.h"
#include "piprocess.h"
#include "pidir.h" #include "pidir.h"
#include "piliterals_string.h"
#include "piprocess.h"
#include "pisysteminfo.h"
#include "pitime_win.h" #include "pitime_win.h"
#include "pitranslator.h"
#include <unistd.h>
#ifdef WINDOWS #ifdef WINDOWS
# include <psapi.h> # include <psapi.h>
# include <tlhelp32.h> # include <tlhelp32.h>
@@ -54,7 +58,8 @@ PRIVATE_DEFINITION_START(PISystemMonitor)
# else # else
llong llong
# endif # endif
cpu_u_cur, cpu_u_prev, cpu_s_cur, cpu_s_prev; cpu_u_cur,
cpu_u_prev, cpu_s_cur, cpu_s_prev;
PIString proc_dir; PIString proc_dir;
PIFile file, filem; PIFile file, filem;
# else # else
@@ -82,7 +87,7 @@ PISystemMonitor::PISystemMonitor(): PIThread() {
PRIVATE->mem_cnt.cb = sizeof(PRIVATE->mem_cnt); PRIVATE->mem_cnt.cb = sizeof(PRIVATE->mem_cnt);
# endif # endif
#endif #endif
setName("system_monitor"); setName("system_monitor"_a);
} }
@@ -92,7 +97,7 @@ PISystemMonitor::~PISystemMonitor() {
#ifndef MICRO_PIP #ifndef MICRO_PIP
bool PISystemMonitor::startOnProcess(int pID, int interval_ms) { bool PISystemMonitor::startOnProcess(int pID, PISystemTime interval) {
stop(); stop();
pID_ = pID; pID_ = pID;
Pool::instance()->add(this); Pool::instance()->add(this);
@@ -103,29 +108,29 @@ bool PISystemMonitor::startOnProcess(int pID, int interval_ms) {
PRIVATE->file.open(PRIVATE->proc_dir + "stat", PIIODevice::ReadOnly); PRIVATE->file.open(PRIVATE->proc_dir + "stat", PIIODevice::ReadOnly);
PRIVATE->filem.open(PRIVATE->proc_dir + "statm", PIIODevice::ReadOnly); PRIVATE->filem.open(PRIVATE->proc_dir + "statm", PIIODevice::ReadOnly);
if (!PRIVATE->file.isOpened()) { if (!PRIVATE->file.isOpened()) {
piCoutObj << "Can`t find process with ID = " << pID_ << "!"; piCoutObj << "Can`t find process with ID = %1!"_tr("PISystemMonitor").arg(pID_);
return false; return false;
} }
# endif # endif
# else # else
PRIVATE->hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID_); PRIVATE->hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID_);
if (PRIVATE->hProc == 0) { if (PRIVATE->hProc == 0) {
piCoutObj << "Can`t open process with ID = " << pID_ << "," << errorString(); piCoutObj << "Can`t open process with ID = %1, %2!"_tr("PISystemMonitor").arg(pID_).arg(errorString());
return false; return false;
} }
PRIVATE->tm.reset(); PRIVATE->tm.reset();
# endif # endif
return start(interval_ms); return start(interval);
} }
#endif #endif
bool PISystemMonitor::startOnSelf(int interval_ms) { bool PISystemMonitor::startOnSelf(PISystemTime interval) {
#ifndef MICRO_PIP #ifndef MICRO_PIP
bool ret = startOnProcess(PIProcess::currentPID(), interval_ms); bool ret = startOnProcess(PIProcess::currentPID(), interval);
cycle = -1; cycle = -1;
#else #else
bool ret = start(interval_ms); bool ret = start(interval);
#endif #endif
return ret; return ret;
} }
@@ -147,7 +152,7 @@ void PISystemMonitor::setStatistic(const PISystemMonitor::ProcessStats & s) {
void PISystemMonitor::stop() { void PISystemMonitor::stop() {
PIThread::stop(); PIThread::stopAndWait();
#ifdef WINDOWS #ifdef WINDOWS
if (PRIVATE->hProc != 0) { if (PRIVATE->hProc != 0) {
CloseHandle(PRIVATE->hProc); CloseHandle(PRIVATE->hProc);
@@ -176,19 +181,18 @@ void PISystemMonitor::run() {
__PIThreadCollection * pitc = __PIThreadCollection::instance(); __PIThreadCollection * pitc = __PIThreadCollection::instance();
pitc->lock(); pitc->lock();
PIVector<PIThread *> tv = pitc->threads(); PIVector<PIThread *> tv = pitc->threads();
piForeach (PIThread * t, tv) for (auto * t: tv)
if (t->isPIObject()) if (t->isPIObject()) tbid[t->tid()] = t->name();
tbid[t->tid()] = t->name();
pitc->unlock(); pitc->unlock();
// piCout << tbid.keys().toType<uint>(); // piCout << tbid.keys().toType<uint>();
ProcessStats tstat; ProcessStats tstat;
tstat.ID = pID_; tstat.ID = pID_;
#ifdef MICRO_PIP #ifdef MICRO_PIP
piForeach (PIThread * t, tv) for (auto * t: tv)
if (t->isPIObject()) if (t->isPIObject()) gatherThread(t->tid());
gatherThread(t->tid());
#else #else
# ifndef WINDOWS # ifndef WINDOWS
double delay_ms = delay_.toMilliseconds();
tbid[pID_] = "main"; tbid[pID_] = "main";
# ifdef MAC_OS # ifdef MAC_OS
rusage_info_current ru; rusage_info_current ru;
@@ -202,13 +206,13 @@ void PISystemMonitor::run() {
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur; PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time); PRIVATE->cpu_u_cur = uint64toST(ru.ri_user_time);
PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time); PRIVATE->cpu_s_cur = uint64toST(ru.ri_system_time);
tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_; tstat.cpu_load_system = 100.f * (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev).toMilliseconds() / delay_ms;
tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_; tstat.cpu_load_user = 100.f * (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
cycle = 0; cycle = 0;
//piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_; // piCout << (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev).toMilliseconds() / delay_ms;
# else # else
PRIVATE->file.seekToBegin(); PRIVATE->file.seekToBegin();
PIString str(PRIVATE->file.readAll(true)); PIString str = PIString::fromAscii(PRIVATE->file.readAll(true));
int si = str.find('(') + 1, fi = 0, cc = 1; int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) { for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++; if (str[i] == '(') cc++;
@@ -235,8 +239,8 @@ void PISystemMonitor::run() {
PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur; PRIVATE->cpu_s_prev = PRIVATE->cpu_s_cur;
PRIVATE->cpu_u_cur = sl[12].toLLong(); PRIVATE->cpu_u_cur = sl[12].toLLong();
PRIVATE->cpu_s_cur = sl[13].toLLong(); PRIVATE->cpu_s_cur = sl[13].toLLong();
tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ / 1000.); tstat.cpu_load_system = (PRIVATE->cpu_s_cur - PRIVATE->cpu_s_prev) / (delay_ms / 1000.);
tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ / 1000.); tstat.cpu_load_user = (PRIVATE->cpu_u_cur - PRIVATE->cpu_u_prev) / (delay_ms / 1000.);
tstat.cpu_load_system /= cpu_count; tstat.cpu_load_system /= cpu_count;
tstat.cpu_load_user /= cpu_count; tstat.cpu_load_user /= cpu_count;
cycle = 0; cycle = 0;
@@ -246,7 +250,7 @@ void PISystemMonitor::run() {
// piCout << sl[0] << sl[12] << sl[13]; // piCout << sl[0] << sl[12] << sl[13];
PRIVATE->filem.seekToBegin(); PRIVATE->filem.seekToBegin();
str = PRIVATE->filem.readAll(true); str = PIString::fromAscii(PRIVATE->filem.readAll(true));
sl = str.split(" "); sl = str.split(" ");
if (sl.size_s() < 6) return; if (sl.size_s() < 6) return;
tstat.virtual_memsize = sl[0].toLong() * page_size; tstat.virtual_memsize = sl[0].toLong() * page_size;
@@ -256,9 +260,8 @@ void PISystemMonitor::run() {
tstat.physical_memsize = tstat.resident_memsize - tstat.share_memsize; tstat.physical_memsize = tstat.resident_memsize - tstat.share_memsize;
PIVector<PIFile::FileInfo> tld = PIDir(PRIVATE->proc_dir + "task").entries(); PIVector<PIFile::FileInfo> tld = PIDir(PRIVATE->proc_dir + "task").entries();
piForeachC (PIFile::FileInfo & i, tld) { for (const auto & i: tld) {
if (i.flags[PIFile::FileInfo::Dot] || i.flags[PIFile::FileInfo::DotDot]) if (i.flags[PIFile::FileInfo::Dot] || i.flags[PIFile::FileInfo::DotDot]) continue;
continue;
gatherThread(i.name().toInt()); gatherThread(i.name().toInt());
} }
# endif # endif
@@ -352,9 +355,8 @@ void PISystemMonitor::gatherThread(llong id) {
# ifndef WINDOWS # ifndef WINDOWS
PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat"); PIFile f(PRIVATE->proc_dir + "task/" + PIString::fromNumber(id) + "/stat");
// piCout << f.path(); // piCout << f.path();
if (!f.open(PIIODevice::ReadOnly)) if (!f.open(PIIODevice::ReadOnly)) return;
return; PIString str = PIString::fromAscii(f.readAll(true));
PIString str = f.readAll(true);
int si = str.find('(') + 1, fi = 0, cc = 1; int si = str.find('(') + 1, fi = 0, cc = 1;
for (int i = si; i < str.size_s(); ++i) { for (int i = si; i < str.size_s(); ++i) {
if (str[i] == '(') cc++; if (str[i] == '(') cc++;
@@ -375,12 +377,12 @@ void PISystemMonitor::gatherThread(llong id) {
FILETIME times[4]; FILETIME times[4];
HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id)); HANDLE thdl = OpenThread(THREAD_QUERY_INFORMATION, FALSE, DWORD(id));
if (!thdl) { if (!thdl) {
piCout << "[PISystemMonitor] gatherThread(" << id << "):: OpenThread() error:" << errorString(); piCoutObj << "GatherThread(" << id << "):: OpenThread() error:" << errorString();
return; return;
} }
if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) { if (GetThreadTimes(thdl, &(times[0]), &(times[1]), &(times[2]), &(times[3])) == 0) {
CloseHandle(thdl); CloseHandle(thdl);
piCout << "[PISystemMonitor] gatherThread(" << id << "):: GetThreadTimes() error:" << errorString(); piCoutObj << "GatherThread(" << id << "):: GetThreadTimes() error:" << errorString();
return; return;
} }
CloseHandle(thdl); CloseHandle(thdl);
@@ -395,15 +397,15 @@ void PISystemMonitor::gatherThread(llong id) {
float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) { float PISystemMonitor::calcThreadUsage(PISystemTime & t_new, PISystemTime & t_old) {
if (delay_ <= 0) return -1.; if (delay_.isNull()) return -1.;
return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_), 0.f, 100.f); return piClampf(100. * ((t_new - t_old).toMilliseconds() / delay_.toMilliseconds()), 0.f, 100.f);
} }
ullong PISystemMonitor::totalRAM() { ullong PISystemMonitor::totalRAM() {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
multi_heap_info_t heap_info; multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t)); piZeroMemory(heap_info);
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT); heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes + heap_info.total_free_bytes; return heap_info.total_allocated_bytes + heap_info.total_free_bytes;
#endif #endif
@@ -414,7 +416,7 @@ ullong PISystemMonitor::totalRAM() {
ullong PISystemMonitor::freeRAM() { ullong PISystemMonitor::freeRAM() {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
multi_heap_info_t heap_info; multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t)); piZeroMemory(heap_info);
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT); heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_free_bytes; return heap_info.total_free_bytes;
#endif #endif
@@ -425,7 +427,7 @@ ullong PISystemMonitor::freeRAM() {
ullong PISystemMonitor::usedRAM() { ullong PISystemMonitor::usedRAM() {
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
multi_heap_info_t heap_info; multi_heap_info_t heap_info;
memset(&heap_info, 0, sizeof(multi_heap_info_t)); piZeroMemory(heap_info);
heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT); heap_caps_get_info(&heap_info, MALLOC_CAP_8BIT);
return heap_info.total_allocated_bytes; return heap_info.total_allocated_bytes;
#endif #endif
@@ -433,8 +435,6 @@ ullong PISystemMonitor::usedRAM() {
} }
PISystemMonitor::Pool * PISystemMonitor::Pool::instance() { PISystemMonitor::Pool * PISystemMonitor::Pool::instance() {
static Pool ret; static Pool ret;
return &ret; return &ret;

View File

@@ -1,5 +1,5 @@
/*! \file pisystemmonitor.h /*! \file pisystemmonitor.h
* \ingroup System * \ingroup Application
* \~\brief * \~\brief
* \~english System resources monitoring * \~english System resources monitoring
* \~russian Мониторинг ресурсов системы * \~russian Мониторинг ресурсов системы
@@ -26,17 +26,18 @@
#ifndef PISYSTEMMONITOR_H #ifndef PISYSTEMMONITOR_H
#define PISYSTEMMONITOR_H #define PISYSTEMMONITOR_H
#include "pithread.h"
#include "pifile.h" #include "pifile.h"
#include "pithread.h"
//! \ingroup System //! \ingroup Application
//! \~\brief //! \~\brief
//! \~english Process monitoring. //! \~english Process monitoring.
//! \~russian Мониторинг процесса. //! \~russian Мониторинг процесса.
class PIP_EXPORT PISystemMonitor: public PIThread { class PIP_EXPORT PISystemMonitor: public PIThread {
PIOBJECT_SUBCLASS(PISystemMonitor, PIThread); PIOBJECT_SUBCLASS(PISystemMonitor, PIThread);
friend class PIIntrospectionServer; friend class PIIntrospectionServer;
public: public:
//! \~english Constructs unassigned %PISystemMonitor //! \~english Constructs unassigned %PISystemMonitor
//! \~russian Создает непривязанный %PISystemMonitor //! \~russian Создает непривязанный %PISystemMonitor
@@ -45,12 +46,11 @@ public:
~PISystemMonitor(); ~PISystemMonitor();
#pragma pack(push, 1) #pragma pack(push, 1)
//! \ingroup System //! \ingroup Application
//! \~\brief //! \~\brief
//! \~english Process statistics (fixed-size fields). //! \~english Process statistics (fixed-size fields).
//! \~russian Статистика процесса (фиксированные поля). //! \~russian Статистика процесса (фиксированные поля).
struct PIP_EXPORT ProcessStatsFixed { struct PIP_EXPORT ProcessStatsFixed {
//! \~english PID //! \~english PID
//! \~russian PID //! \~russian PID
int ID = 0; int ID = 0;
@@ -116,12 +116,11 @@ public:
float cpu_load_user = 0.f; float cpu_load_user = 0.f;
}; };
//! \ingroup System //! \ingroup Application
//! \~\brief //! \~\brief
//! \~english Thread statistics (fixed-size fields). //! \~english Thread statistics (fixed-size fields).
//! \~russian Статистика потока (фиксированные поля). //! \~russian Статистика потока (фиксированные поля).
struct PIP_EXPORT ThreadStatsFixed { struct PIP_EXPORT ThreadStatsFixed {
//! \~english TID //! \~english TID
//! \~russian TID //! \~russian TID
llong id = 0; llong id = 0;
@@ -152,12 +151,11 @@ public:
}; };
#pragma pack(pop) #pragma pack(pop)
//! \ingroup System //! \ingroup Application
//! \~\brief //! \~\brief
//! \~english Process statistics. //! \~english Process statistics.
//! \~russian Статистика процесса. //! \~russian Статистика процесса.
struct PIP_EXPORT ProcessStats: ProcessStatsFixed { struct PIP_EXPORT ProcessStats: ProcessStatsFixed {
//! \~english Fill human-readable fields //! \~english Fill human-readable fields
//! \~russian Заполнить читаемые поля //! \~russian Заполнить читаемые поля
void makeStrings(); void makeStrings();
@@ -191,12 +189,11 @@ public:
PIString data_memsize_readable; PIString data_memsize_readable;
}; };
//! \ingroup System //! \ingroup Application
//! \~\brief //! \~\brief
//! \~english Thread statistics. //! \~english Thread statistics.
//! \~russian Статистика потока. //! \~russian Статистика потока.
struct PIP_EXPORT ThreadStats: ThreadStatsFixed { struct PIP_EXPORT ThreadStats: ThreadStatsFixed {
//! \~english Name //! \~english Name
//! \~russian Имя //! \~russian Имя
PIString name; PIString name;
@@ -206,12 +203,12 @@ public:
//! \~english Starts monitoring of process with PID "pID" and update interval "interval_ms" milliseconds //! \~english Starts monitoring of process with PID "pID" and update interval "interval_ms" milliseconds
//! \~russian Начинает мониторинг процесса с PID "pID" и интервалом обновления "interval_ms" миллисекунд //! \~russian Начинает мониторинг процесса с PID "pID" и интервалом обновления "interval_ms" миллисекунд
bool startOnProcess(int pID, int interval_ms = 1000); bool startOnProcess(int pID, PISystemTime interval = PISystemTime::fromSeconds(1.));
#endif #endif
//! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds //! \~english Starts monitoring of application process with update interval "interval_ms" milliseconds
//! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд //! \~russian Начинает мониторинг процесса приложения с интервалом обновления "interval_ms" миллисекунд
bool startOnSelf(int interval_ms = 1000); bool startOnSelf(PISystemTime interval = PISystemTime::fromSeconds(1.));
//! \~english Stop monitoring //! \~english Stop monitoring
//! \~russian Останавливает мониторинг //! \~russian Останавливает мониторинг
@@ -263,17 +260,17 @@ private:
class PIP_EXPORT Pool { class PIP_EXPORT Pool {
friend class PISystemMonitor; friend class PISystemMonitor;
public: public:
static Pool * instance(); static Pool * instance();
PISystemMonitor * getByPID(int pID); PISystemMonitor * getByPID(int pID);
private: private:
void add(PISystemMonitor * sm); void add(PISystemMonitor * sm);
void remove(PISystemMonitor * sm); void remove(PISystemMonitor * sm);
PIMap<int, PISystemMonitor *> sysmons; PIMap<int, PISystemMonitor *> sysmons;
PIMutex mutex; PIMutex mutex;
}; };
}; };
//! \relatesalso PICout //! \relatesalso PICout
@@ -281,8 +278,7 @@ private:
//! \~russian Оператор вывода в \a PICout //! \~russian Оператор вывода в \a PICout
inline PICout operator<<(PICout s, const PISystemMonitor::ThreadStats & v) { inline PICout operator<<(PICout s, const PISystemMonitor::ThreadStats & v) {
s.saveAndSetControls(0); s.saveAndSetControls(0);
s << "ThreadInfo(\"" << v.name << "\", created " << v.created s << "ThreadInfo(\"" << v.name << "\", created " << v.created << ", work " << v.work_time.toMilliseconds() << " ms"
<< ", work " << v.work_time.toMilliseconds() << " ms"
<< ", kernel " << v.kernel_time.toMilliseconds() << " ms" << ", kernel " << v.kernel_time.toMilliseconds() << " ms"
<< ", user " << v.user_time.toMilliseconds() << " ms" << ", user " << v.user_time.toMilliseconds() << " ms"
<< ")\n"; << ")\n";
@@ -295,8 +291,7 @@ inline PICout operator <<(PICout s, const PISystemMonitor::ThreadStats & v) {
//! \~english Store operator. //! \~english Store operator.
//! \~russian Оператор сохранения. //! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PISystemMonitor::ProcessStats) { BINARY_STREAM_WRITE(PISystemMonitor::ProcessStats) {
s << PIMemoryBlock(&v, sizeof(PISystemMonitor::ProcessStatsFixed)) s << PIMemoryBlock(&v, sizeof(PISystemMonitor::ProcessStatsFixed)) << v.exec_name << v.state;
<< v.exec_name << v.state;
return s; return s;
} }
@@ -304,8 +299,7 @@ BINARY_STREAM_WRITE(PISystemMonitor::ProcessStats) {
//! \~english Restore operator. //! \~english Restore operator.
//! \~russian Оператор извлечения. //! \~russian Оператор извлечения.
BINARY_STREAM_READ(PISystemMonitor::ProcessStats) { BINARY_STREAM_READ(PISystemMonitor::ProcessStats) {
s >> PIMemoryBlock(&v, sizeof(PISystemMonitor::ProcessStatsFixed)) s >> PIMemoryBlock(&v, sizeof(PISystemMonitor::ProcessStatsFixed)) >> v.exec_name >> v.state;
>> v.exec_name >> v.state;
v.makeStrings(); v.makeStrings();
return s; return s;
} }
@@ -314,8 +308,7 @@ BINARY_STREAM_READ (PISystemMonitor::ProcessStats) {
//! \~english Store operator. //! \~english Store operator.
//! \~russian Оператор сохранения. //! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PISystemMonitor::ThreadStats) { BINARY_STREAM_WRITE(PISystemMonitor::ThreadStats) {
s << PIMemoryBlock(&v, sizeof(PISystemMonitor::ThreadStatsFixed)) s << PIMemoryBlock(&v, sizeof(PISystemMonitor::ThreadStatsFixed)) << v.name;
<< v.name;
return s; return s;
} }
@@ -323,8 +316,7 @@ BINARY_STREAM_WRITE(PISystemMonitor::ThreadStats) {
//! \~english Restore operator. //! \~english Restore operator.
//! \~russian Оператор извлечения. //! \~russian Оператор извлечения.
BINARY_STREAM_READ(PISystemMonitor::ThreadStats) { BINARY_STREAM_READ(PISystemMonitor::ThreadStats) {
s >> PIMemoryBlock(&v, sizeof(PISystemMonitor::ThreadStatsFixed)) s >> PIMemoryBlock(&v, sizeof(PISystemMonitor::ThreadStatsFixed)) >> v.name;
>> v.name;
return s; return s;
} }

View File

@@ -0,0 +1,116 @@
/*
PIP - Platform Independent Primitives
Translation support
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pitranslator.h"
#include "pidir.h"
#include "pifile.h"
#include "piliterals_string.h"
#include "pitranslator_p.h"
#include "pivaluetree_conversions.h"
//! \class PITranslator pitranslator.h
//! \details
//! \~english \section PITranslator_sec0 Synopsis
//! \~russian \section PITranslator_sec0 Краткий обзор
//! \~english
//!
//! \~russian
//!
PRIVATE_DEFINITION_START(PITranslator)
PITranslatorPrivate::Translation content;
PRIVATE_DEFINITION_END(PITranslator)
PIString PITranslator::tr(const PIString & in, const PIString & context) {
return instance()->PRIVATEWB->content.translate(in, context);
}
void PITranslator::clear() {
instance()->PRIVATEWB->content.clear();
}
void PITranslator::loadLang(const PIString & short_lang, PIString dir) {
if (dir.isEmpty()) dir = PIDir::current().absolute("lang");
clear();
auto files = PIDir(dir).entries();
for (const auto & f: files) {
if (!f.baseName().endsWith(short_lang)) continue;
loadFile(f.path);
}
piCout << "Loaded %1 string for lang \"%2\""_a.arg(instance()->PRIVATEWB->content.count()).arg(short_lang);
/*auto s = instance();
auto vt = PIValueTreeConversions::fromText(getBuiltinConfig());
auto lang = vt.child(short_lang.toLowerCase().trim());
for (const auto & cn: lang.children()) {
auto c = s->PRIVATEWB->content.createContext(cn.name());
for (const auto & s: cn.children())
c->add(s.name(), s.value().toString());
}*/
}
void PITranslator::loadConfig(const PIString & content) {
auto s = instance();
auto lang = PIValueTreeConversions::fromText(content);
for (const auto & cn: lang.children()) {
auto c = s->PRIVATEWB->content.createContext(cn.name());
for (const auto & s: cn.children())
c->add(s.name(), s.value().toString());
}
auto c = s->PRIVATEWB->content.createContext("");
for (const auto & s: lang.children()) {
if (s.hasChildren()) continue;
c->add(s.name(), s.value().toString());
}
}
bool PITranslator::load(const PIByteArray & content) {
return instance()->PRIVATEWB->content.load(content);
}
bool PITranslator::loadFile(const PIString & path) {
PIFile f(path, PIIODevice::ReadOnly);
if (f.isClosed()) return false;
if (!PITranslatorPrivate::checkHeader(&f)) return false;
auto data = f.readAll();
data.remove(0, PITranslatorPrivate::headerSize());
return load(data);
}
PITranslator::PITranslator() {}
PITranslator::~PITranslator() {
PRIVATE->content.clear();
}
PITranslator * PITranslator::instance() {
static PITranslator ret;
return &ret;
}

View File

@@ -0,0 +1,98 @@
/*! \file pitranslator.h
* \ingroup Application
* \~\brief
* \~english Translation support
* \~russian Поддержка перевода
*/
/*
PIP - Platform Independent Primitives
Translation support
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pitranslator_H
#define pitranslator_H
#include "pistring.h"
#define piTr PITranslator::tr
#define piTrNoOp PITranslator::trNoOp
//! \ingroup Application
//! \~\brief
//! \~english Translation support
//! \~russian Поддержка перевода
class PIP_EXPORT PITranslator {
public:
static PIString tr(const PIString & in, const PIString & context = {});
static PIString tr(const char * in, const PIString & context = {}) { return tr(PIString::fromUTF8(in), context); }
static PIString trNoOp(const PIString & in, const PIString & context = {}) { return in; }
static PIString trNoOp(const char * in, const PIString & context = {}) { return trNoOp(PIString::fromUTF8(in), context); }
static void clear();
static void loadLang(const PIString & short_lang, PIString dir = {});
static void loadConfig(const PIString & content);
static bool load(const PIByteArray & content);
static bool loadFile(const PIString & path);
private:
PITranslator();
~PITranslator();
NO_COPY_CLASS(PITranslator)
PRIVATE_DECLARATION(PIP_EXPORT)
static PITranslator * instance();
};
class PIStringContextTr {
public:
PIStringContextTr(PIString && s): _s(s) {}
operator PIString() const { return PITranslator::tr(_s); }
PIString operator()(const PIString & ctx = {}) const { return PITranslator::tr(_s, ctx); }
private:
PIString _s;
};
class PIStringContextTrNoOp {
public:
PIStringContextTrNoOp(PIString && s): _s(s) {}
operator PIString() const { return _s; }
PIString operator()(const PIString & ctx = {}) const { return _s; }
private:
PIString _s;
};
//! \~\brief
//! \~english Translate string with \a PITranslator::tr()
//! \~russian Перевести строку с помощью \a PITranslator::tr()
inline PIStringContextTr operator""_tr(const char * v, size_t sz) {
return PIStringContextTr(PIString::fromUTF8(v, sz));
}
//! \~\brief
//! \~english Translate string with \a PITranslator::tr()
//! \~russian Перевести строку с помощью \a PITranslator::tr()
inline PIStringContextTrNoOp operator""_trNoOp(const char * v, size_t sz) {
return PIStringContextTrNoOp(PIString::fromUTF8(v, sz));
}
#endif

View File

@@ -0,0 +1,124 @@
/*
PIP - Platform Independent Primitives
Translation private
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pitranslator_p.h"
#include "pichunkstream.h"
#include "piiodevice.h"
constexpr int currentVersion = 1;
const PIByteArray fileHeader("PIPBTF", 6);
void PITranslatorPrivate::Context::add(const PIMap<uint, PIString> & sm) {
auto it = sm.makeIterator();
while (it.next())
strings[it.key()] = it.value();
}
void PITranslatorPrivate::Translation::clear() {
piDeleteAll(contexts.values());
contexts.clear();
lang.clear();
}
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(const PIString & context) {
return createContext(context.hash());
}
PITranslatorPrivate::Context * PITranslatorPrivate::Translation::createContext(uint hash) {
auto & ret(contexts[hash]);
if (!ret) ret = new Context();
return ret;
}
PIString PITranslatorPrivate::Translation::translate(const PIString & in, const PIString & context) {
auto c = contexts.value(context.hash());
if (!c) return in;
return c->strings.value(in.hash(), in);
}
bool PITranslatorPrivate::Translation::load(const PIByteArray & data) {
if (data.size_s() <= 4) return false;
PIChunkStream cs(data);
Context * ctx = nullptr;
PIMap<uint, PIString> strings;
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: {
int version = cs.getData<int>();
if (version != currentVersion) {
piCout << "Invalid translation version!";
return false;
}
} break;
case 3: {
uint ctx_hash = cs.getData<uint>();
ctx = createContext(ctx_hash);
} break;
case 4: {
cs.get(strings);
if (ctx) ctx->add(strings);
} break;
}
}
return true;
}
int PITranslatorPrivate::Translation::count() const {
int ret = 0;
auto cit = contexts.makeIterator();
while (cit.next())
ret += cit.value()->strings.size_s();
return ret;
}
PIByteArray PITranslatorPrivate::Translation::save() {
PIChunkStream cs;
cs.add(1, currentVersion).add(2, lang);
auto cit = contexts.makeIterator();
while (cit.next()) {
cs.add(3, cit.key()).add(4, cit.value()->strings);
}
return cs.data();
}
int PITranslatorPrivate::headerSize() {
return fileHeader.size_s();
}
bool PITranslatorPrivate::checkHeader(PIIODevice * d) {
if (!d) return false;
return d->read(fileHeader.size_s()) == fileHeader;
}
void PITranslatorPrivate::writeHeader(PIIODevice * d) {
if (!d) return;
d->write(fileHeader);
}

View File

@@ -0,0 +1,53 @@
/*
PIP - Platform Independent Primitives
Translation private
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef pitranslator_p_H
#define pitranslator_p_H
#include "pistring.h"
class PIIODevice;
namespace PITranslatorPrivate {
struct PIP_EXPORT Context {
void add(const PIString & in, const PIString & out) { strings[in.hash()] = out; }
void add(const PIMap<uint, PIString> & sm);
PIMap<uint, PIString> strings;
};
struct PIP_EXPORT Translation {
void clear();
Context * createContext(const PIString & context);
Context * createContext(uint hash);
PIString translate(const PIString & in, const PIString & context);
bool load(const PIByteArray & data);
int count() const;
PIByteArray save();
PIString lang;
PIMap<uint, Context *> contexts;
};
PIP_EXPORT int headerSize();
PIP_EXPORT bool checkHeader(PIIODevice * d);
PIP_EXPORT void writeHeader(PIIODevice * d);
} // namespace PITranslatorPrivate
#endif

View File

@@ -0,0 +1,69 @@
/*! \file piclientserver_client.h
* \ingroup ClientServer
* \~\brief
* \~english
* \~russian
*/
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef piclientserver_client_H
#define piclientserver_client_H
#include "piclientserver_client_base.h"
namespace PIClientServer {
// ServerClient
class PIP_CLIENT_SERVER_EXPORT ServerClient: public ClientBase {
friend class Server;
NO_COPY_CLASS(ServerClient);
public:
ServerClient() {}
protected:
virtual void aboutDelete() {}
private:
void createForServer(Server * parent, PIEthernet * tcp_);
};
// Client
class PIP_CLIENT_SERVER_EXPORT Client: public ClientBase {
NO_COPY_CLASS(Client);
public:
Client();
~Client();
void connect(PINetworkAddress addr);
protected:
private:
};
} // namespace PIClientServer
#endif

View File

@@ -0,0 +1,88 @@
/*! \file piclientserver_client_base.h
* \ingroup ClientServer
* \~\brief
* \~english
* \~russian
*/
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef piclientserver_client_base_H
#define piclientserver_client_base_H
#include "pidiagnostics.h"
#include "pip_client_server_export.h"
#include "pistreampacker.h"
class PIEthernet;
namespace PIClientServer {
class Server;
class ClientInterface {};
// template<bool EnableDiagnostics = false>
class PIP_CLIENT_SERVER_EXPORT ClientBase {
friend class Server;
NO_COPY_CLASS(ClientBase);
public:
ClientBase();
virtual ~ClientBase();
const PIEthernet * getTCP() const { return tcp; }
void close();
void stopAndWait();
int write(const void * d, const size_t s);
int write(const PIByteArray & ba) { return write(ba.data(), ba.size()); }
void enableDiagnostics();
PIDiagnostics::State diagnostics() const;
int receivePacketProgress() const;
const PIStreamPackerConfig & configuration() const { return stream.configuration(); }
PIStreamPackerConfig & configuration() { return stream.configuration(); }
void setConfiguration(const PIStreamPackerConfig & config) { stream.setConfiguration(config); }
protected:
virtual void readed(PIByteArray data) {}
virtual void connected() {}
virtual void disconnected() {}
virtual void receivePacketStart(int size) {}
virtual void receivePacketEnd() {}
void init();
bool own_tcp = false;
std::atomic_bool can_write = {true};
PIEthernet * tcp = nullptr;
private:
void destroy();
PIStreamPacker stream;
mutable PIMutex write_mutex;
PIDiagnostics * diag = nullptr;
};
} // namespace PIClientServer
#endif

View File

@@ -0,0 +1,79 @@
/*! \file piclientserver_server.h
* \ingroup ClientServer
* \~\brief
* \~english
* \~russian
*/
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef piclientserver_server_H
#define piclientserver_server_H
#include "pimutex.h"
#include "pinetworkaddress.h"
#include "pip_client_server_export.h"
#include "pistreampacker.h"
#include "pithreadnotifier.h"
class PIEthernet;
class PIThread;
namespace PIClientServer {
class ServerClient;
class PIP_CLIENT_SERVER_EXPORT Server: public PIStreamPackerConfig {
friend class ServerClient;
NO_COPY_CLASS(Server);
public:
Server();
virtual ~Server();
void listen(PINetworkAddress addr);
void listenAll(ushort port) { listen({0, port}); }
void stopServer();
void closeAll();
int getMaxClients() const { return max_clients; }
void setMaxClients(int new_max_clients);
int clientsCount() const;
void forEachClient(std::function<void(ServerClient *)> func);
void setClientFactory(std::function<ServerClient *()> f) { client_factory = f; }
private:
void newClient(ServerClient * c);
void clientDisconnected(ServerClient * c);
std::function<ServerClient *()> client_factory;
std::atomic_bool is_closing = {false};
PIEthernet * tcp_server = nullptr;
PIThread * clean_thread = nullptr;
PIThreadNotifier clean_notifier;
PIVector<ServerClient *> clients;
mutable PIMutex clients_mutex;
int max_clients = 1000;
};
} // namespace PIClientServer
#endif

View File

@@ -0,0 +1,57 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//! \defgroup ClientServer ClientServer
//! \~\brief
//! \~english TCP Client-Server
//! \~russian TCP Клиент-Сервер
//!
//! \~\details
//! \~english \section cmake_module_ClientServer Building with CMake
//! \~russian \section cmake_module_ClientServer Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::ClientServer)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides server with clients dispatching for server-side and client for client-side.
//!
//! \~russian
//! Эти файлы предоставляют сервер с диспетчеризацией клиентов для серверной стороны и клиента для клиентской стороны.
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PICLIENTSERVERMODULE_H
#define PICLIENTSERVERMODULE_H
#include "piclientserver_client.h"
#include "piclientserver_server.h"
#endif

View File

@@ -31,8 +31,7 @@
#include "pistreampacker.h" #include "pistreampacker.h"
class PIP_CLOUD_EXPORT PICloudBase class PIP_CLOUD_EXPORT PICloudBase {
{
public: public:
PICloudBase(); PICloudBase();

View File

@@ -32,9 +32,11 @@
//! \brief PICloudClient //! \brief PICloudClient
class PIP_CLOUD_EXPORT PICloudClient: public PIIODevice, public PICloudBase class PIP_CLOUD_EXPORT PICloudClient
{ : public PIIODevice
, public PICloudBase {
PIIODEVICE(PICloudClient, ""); PIIODEVICE(PICloudClient, "");
public: public:
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudClient(); virtual ~PICloudClient();
@@ -43,6 +45,7 @@ public:
void setKeepConnection(bool on); void setKeepConnection(bool on);
bool isConnected() const { return is_connected; } bool isConnected() const { return is_connected; }
ssize_t bytesAvailable() const override { return buff.size(); } ssize_t bytesAvailable() const override { return buff.size(); }
void interrupt() override;
EVENT(connected); EVENT(connected);
EVENT(disconnected); EVENT(disconnected);

View File

@@ -51,8 +51,8 @@
#ifndef PICLOUDMODULE_H #ifndef PICLOUDMODULE_H
#define PICLOUDMODULE_H #define PICLOUDMODULE_H
#include "picloudtcp.h"
#include "picloudclient.h" #include "picloudclient.h"
#include "picloudserver.h" #include "picloudserver.h"
#include "picloudtcp.h"
#endif // PICLOUDMODULE_H #endif // PICLOUDMODULE_H

View File

@@ -30,9 +30,11 @@
#include "piconditionvar.h" #include "piconditionvar.h"
class PIP_CLOUD_EXPORT PICloudServer: public PIIODevice, public PICloudBase class PIP_CLOUD_EXPORT PICloudServer
{ : public PIIODevice
, public PICloudBase {
PIIODEVICE(PICloudServer, ""); PIIODEVICE(PICloudServer, "");
public: public:
//! PICloudServer //! PICloudServer
explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite); explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
@@ -41,9 +43,11 @@ public:
class Client: public PIIODevice { class Client: public PIIODevice {
PIIODEVICE(PICloudServer::Client, ""); PIIODEVICE(PICloudServer::Client, "");
friend class PICloudServer; friend class PICloudServer;
public: public:
Client(PICloudServer * srv = nullptr, uint id = 0); Client(PICloudServer * srv = nullptr, uint id = 0);
virtual ~Client(); virtual ~Client();
protected: protected:
bool openDevice() override; bool openDevice() override;
bool closeDevice() override; bool closeDevice() override;
@@ -51,6 +55,7 @@ public:
ssize_t writeDevice(const void * data, ssize_t size) override; ssize_t writeDevice(const void * data, ssize_t size) override;
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; } DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
ssize_t bytesAvailable() const override { return buff.size(); } ssize_t bytesAvailable() const override { return buff.size(); }
void interrupt() override;
private: private:
void pushBuffer(const PIByteArray & ba); void pushBuffer(const PIByteArray & ba);
@@ -73,6 +78,7 @@ protected:
bool closeDevice() override; bool closeDevice() override;
ssize_t readDevice(void * read_to, ssize_t max_size) override; ssize_t readDevice(void * read_to, ssize_t max_size) override;
ssize_t writeDevice(const void * data, ssize_t max_size) override; ssize_t writeDevice(const void * data, ssize_t max_size) override;
void interrupt() override;
private: private:
EVENT_HANDLER1(void, _readed, PIByteArray &, ba); EVENT_HANDLER1(void, _readed, PIByteArray &, ba);
@@ -81,9 +87,13 @@ private:
int sendData(const PIByteArray & data, uint client_id); int sendData(const PIByteArray & data, uint client_id);
PIVector<Client *> clients_; PIVector<Client *> clients_;
PIVector<Client *> removed_clients_;
PIMap<uint, Client *> index_clients; PIMap<uint, Client *> index_clients;
PITimer ping_timer; PIThread ping_timer;
PIConditionVariable cvar;
PIMutex open_mutex;
mutable PIMutex clients_mutex; mutable PIMutex clients_mutex;
std::atomic_bool is_deleted;
}; };
#endif // PICLOUDSERVER_H #endif // PICLOUDSERVER_H

View File

@@ -26,9 +26,9 @@
#ifndef PICLOUDTCP_H #ifndef PICLOUDTCP_H
#define PICLOUDTCP_H #define PICLOUDTCP_H
#include "pimutex.h"
#include "pip_cloud_export.h" #include "pip_cloud_export.h"
#include "pistring.h" #include "pistring.h"
#include "pimutex.h"
class PIEthernet; class PIEthernet;
@@ -37,7 +37,6 @@ class PIStreamPacker;
namespace PICloud { namespace PICloud {
class PIP_CLOUD_EXPORT TCP { class PIP_CLOUD_EXPORT TCP {
public: public:
enum Version { enum Version {
@@ -91,9 +90,8 @@ private:
PIString server_name; PIString server_name;
PIStreamPacker * streampacker; PIStreamPacker * streampacker;
PIMutex mutex_send; PIMutex mutex_send;
}; };
} } // namespace PICloud
#endif // PICLOUDTCP_H #endif // PICLOUDTCP_H

View File

@@ -18,45 +18,68 @@
*/ */
#include "picodeinfo.h" #include "picodeinfo.h"
#include "pivariant.h" #include "pivariant.h"
PIString PICodeInfo::EnumInfo::memberName(int value_) const { PIString PICodeInfo::EnumInfo::memberName(int value_) const {
piForeachC (PICodeInfo::EnumeratorInfo & e, members) for (const auto & e: members)
if (e.value == value_) if (e.value == value_) return e.name.toString();
return e.name.toString();
return PIString(); return PIString();
} }
int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const { int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
piForeachC (PICodeInfo::EnumeratorInfo & e, members) for (const auto & e: members)
if (e.name.toString() == name_) if (e.name.toString() == name_) return e.value;
return e.value;
return -1; return -1;
} }
PIVariantTypes::Enum PICodeInfo::EnumInfo::toPIVariantEnum() { PIVariantTypes::Enum PICodeInfo::EnumInfo::toPIVariantEnum() {
PIVariantTypes::Enum en(name.toString()); PIVariantTypes::Enum en(name.toString());
for (auto m: members) en << m.toPIVariantEnumerator(); for (auto m: members)
en << m.toPIVariantEnumerator();
if (!en.isEmpty()) en.selectValue(members.front().value); if (!en.isEmpty()) en.selectValue(members.front().value);
return en; return en;
} }
PIMap<PIConstChars, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
PIMap<PIConstChars, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * PICodeInfo::accessTypeFunctions;
bool __PICodeInfoInitializer__::_inited_ = false;
PIVariant PICodeInfo::getMemberAsVariant(const void * p, const char * class_name, const char * member_name) { PIVariant PICodeInfo::getMemberAsVariant(const void * p, const char * class_name, const char * member_name) {
if (!p || !class_name || !member_name || !accessTypeFunctions || !accessValueFunctions) return PIVariant(); if (!p || !class_name || !member_name) return PIVariant();
AccessTypeFunction atf = accessTypeFunctions->value(class_name, (AccessTypeFunction)0); AccessTypeFunction atf = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction) nullptr);
AccessValueFunction avf = accessValueFunctions->value(class_name, (AccessValueFunction)0); AccessValueFunction avf = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction) nullptr);
if (!atf || !avf) return PIVariant(); if (!atf || !avf) return PIVariant();
return PIVariant::fromValue(avf(p, member_name), PIStringAscii(atf(member_name))); return PIVariant::fromValue(avf(p, member_name), PIStringAscii(atf(member_name)));
} }
PICodeInfo::__Storage__::__Storage__() {
classesInfo = new PIMap<PIConstChars, ClassInfo *>;
enumsInfo = new PIMap<PIConstChars, EnumInfo *>;
accessValueFunctions = new PIMap<PIConstChars, AccessValueFunction>;
accessTypeFunctions = new PIMap<PIConstChars, AccessTypeFunction>;
(*enumsInfo)[""] = new EnumInfo();
}
PICodeInfo::__Storage__::~__Storage__() {
piDeleteAll(classesInfo->values());
piDeleteAll(enumsInfo->values());
piDeleteSafety(classesInfo);
piDeleteSafety(enumsInfo);
piDeleteSafety(accessValueFunctions);
piDeleteSafety(accessTypeFunctions);
}
PICodeInfo::__Storage__ * PICodeInfo::__Storage__::instance() {
static __Storage__ ret;
return &ret;
}
PICodeInfo::ClassInfoInterface classesInfo;
PICodeInfo::EnumsInfoInterface enumsInfo;
PICodeInfo::AccessValueFunctionInterface accessValueFunctions;
PICodeInfo::AccessTypeFunctionInterface accessTypeFunctions;

View File

@@ -63,7 +63,12 @@ typedef const char*(*AccessTypeFunction)(const char *);
//! \~english Type information //! \~english Type information
//! \~russian Информация о типе //! \~russian Информация о типе
struct PIP_EXPORT TypeInfo { struct PIP_EXPORT TypeInfo {
TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) {name = n; type = t; flags = f; bits = b;} TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) {
name = n;
type = t;
flags = f;
bits = b;
}
//! \~english Returns if variable if bitfield //! \~english Returns if variable if bitfield
//! \~russian Возвращает битовым ли полем является переменная //! \~russian Возвращает битовым ли полем является переменная
@@ -94,7 +99,6 @@ struct PIP_EXPORT TypeInfo {
//! \~english Method information //! \~english Method information
//! \~russian Информация о методе //! \~russian Информация о методе
struct PIP_EXPORT FunctionInfo { struct PIP_EXPORT FunctionInfo {
//! \~english Custom PIMETA content //! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA //! \~russian Произвольное содержимое PIMETA
MetaMap meta; MetaMap meta;
@@ -155,7 +159,10 @@ struct PIP_EXPORT ClassInfo {
//! \~english Enumerator information //! \~english Enumerator information
//! \~russian Информация об элементе перечисления //! \~russian Информация об элементе перечисления
struct PIP_EXPORT EnumeratorInfo { struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIConstChars & n = PIConstChars(), int v = 0) {name = n; value = v;} EnumeratorInfo(const PIConstChars & n = PIConstChars(), int v = 0) {
name = n;
value = v;
}
PIVariantTypes::Enumerator toPIVariantEnumerator() { return PIVariantTypes::Enumerator(value, name.toString()); } PIVariantTypes::Enumerator toPIVariantEnumerator() { return PIVariantTypes::Enumerator(value, name.toString()); }
//! \~english Custom PIMETA content //! \~english Custom PIMETA content
@@ -175,7 +182,6 @@ struct PIP_EXPORT EnumeratorInfo {
//! \~english Enum information //! \~english Enum information
//! \~russian Информация о перечислении //! \~russian Информация о перечислении
struct PIP_EXPORT EnumInfo { struct PIP_EXPORT EnumInfo {
//! \~english Returns member name with value "value" //! \~english Returns member name with value "value"
//! \~russian Возвращает имя элемента со значением "value" //! \~russian Возвращает имя элемента со значением "value"
PIString memberName(int value) const; PIString memberName(int value) const;
@@ -210,12 +216,14 @@ inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
if (v.flags[Static]) s << "static "; if (v.flags[Static]) s << "static ";
if (v.flags[Const]) s << "const "; if (v.flags[Const]) s << "const ";
s << v.type; s << v.type;
if (!v.name.isEmpty()) if (!v.name.isEmpty()) s << " " << v.name;
s << " " << v.name;
return s; return s;
} }
inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value << " Meta" << v.meta; return s;} inline PICout operator<<(PICout s, const PICodeInfo::EnumeratorInfo & v) {
s << v.name << " = " << v.value << " Meta" << v.meta;
return s;
}
inline PICout operator<<(PICout s, const PICodeInfo::ClassInfo & v) { inline PICout operator<<(PICout s, const PICodeInfo::ClassInfo & v) {
s.saveAndSetControls(0); s.saveAndSetControls(0);
@@ -224,8 +232,10 @@ inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
s << ": "; s << ": ";
bool first = true; bool first = true;
for (const auto & i: v.parents) { for (const auto & i: v.parents) {
if (first) first = false; if (first)
else s << ", "; first = false;
else
s << ", ";
s << i; s << i;
} }
} }
@@ -234,14 +244,15 @@ inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
s << PICoutManipulators::Tab << i.return_type << " " << i.name << "("; s << PICoutManipulators::Tab << i.return_type << " " << i.name << "(";
bool fa = true; bool fa = true;
for (const auto & a: i.arguments) { for (const auto & a: i.arguments) {
if (fa) fa = false; if (fa)
else s << ", "; fa = false;
else
s << ", ";
s << a; s << a;
} }
s << ") Meta" << i.meta << ";\n"; s << ") Meta" << i.meta << ";\n";
} }
if (!v.functions.isEmpty() && !v.variables.isEmpty()) if (!v.functions.isEmpty() && !v.variables.isEmpty()) s << "\n";
s << "\n";
for (const auto & i: v.variables) { for (const auto & i: v.variables) {
s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n"; s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n";
} }
@@ -255,8 +266,10 @@ inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
s << "enum " << v.name << " Meta" << v.meta << " {\n"; s << "enum " << v.name << " Meta" << v.meta << " {\n";
for (const auto & i: v.members) { for (const auto & i: v.members) {
bool f = true; bool f = true;
if (f) f = false; if (f)
else s << ", "; f = false;
else
s << ", ";
s << PICoutManipulators::Tab << i << "\n"; s << PICoutManipulators::Tab << i << "\n";
} }
s << "}\n"; s << "}\n";
@@ -265,28 +278,98 @@ inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
} }
//! \~english Pointer to single storage of PICodeInfo::ClassInfo, access by name class PIP_EXPORT __Storage__ {
//! \~russian Указатель на единое хренилище PICodeInfo::ClassInfo, доступ по имени __Storage__();
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::ClassInfo * > * classesInfo; ~__Storage__();
//! \~english Pointer to single storage of PICodeInfo::EnumInfo, access by name public:
//! \~russian Указатель на единое хренилище PICodeInfo::EnumInfo, доступ по имени static __Storage__ * instance();
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::EnumInfo * > * enumsInfo;
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions; PIMap<PIConstChars, PICodeInfo::ClassInfo *> * classesInfo;
PIMap<PIConstChars, PICodeInfo::EnumInfo *> * enumsInfo;
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
private:
NO_COPY_CLASS(__Storage__)
};
class PIP_EXPORT __StorageAccess__ {
public:
//! \~english Getter for single storage of PICodeInfo::ClassInfo, access by name
//! \~russian Доступ к единому хранилищу PICodeInfo::ClassInfo, доступ по имени
static const PIMap<PIConstChars, PICodeInfo::ClassInfo *> & classes() { return *(__Storage__::instance()->classesInfo); }
//! \~english Getter for single storage of PICodeInfo::EnumInfo, access by name
//! \~russian Доступ к единому хранилищу хранилище PICodeInfo::EnumInfo, доступ по имени
static const PIMap<PIConstChars, PICodeInfo::EnumInfo *> & enums() { return *(__Storage__::instance()->enumsInfo); }
static const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> & accessValueFunctions() {
return *(__Storage__::instance()->accessValueFunctions);
}
static const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> & accessTypeFunctions() {
return *(__Storage__::instance()->accessTypeFunctions);
}
};
#define PICODEINFO PICodeInfo::__StorageAccess__
class PIP_EXPORT ClassInfoInterface {
public:
const PIMap<PIConstChars, PICodeInfo::ClassInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::classes()") {
return __Storage__::instance()->classesInfo;
}
};
static ClassInfoInterface classesInfo;
class PIP_EXPORT EnumsInfoInterface {
public:
const PIMap<PIConstChars, PICodeInfo::EnumInfo *> * operator->() const DEPRECATEDM("use PICODEINFO::enums()") {
return __Storage__::instance()->enumsInfo;
}
};
static EnumsInfoInterface enumsInfo;
class PIP_EXPORT AccessValueFunctionInterface {
public:
const PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessValueFunctions()") {
return __Storage__::instance()->accessValueFunctions;
}
};
static AccessValueFunctionInterface accessValueFunctions;
class PIP_EXPORT AccessTypeFunctionInterface {
public:
const PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * operator->() const DEPRECATEDM("use PICODEINFO::accessTypeFunctions()") {
return __Storage__::instance()->accessTypeFunctions;
}
};
static AccessTypeFunctionInterface accessTypeFunctions;
STATIC_INITIALIZER_BEGIN
NO_UNUSED(classesInfo);
NO_UNUSED(enumsInfo);
NO_UNUSED(accessValueFunctions);
NO_UNUSED(accessTypeFunctions);
STATIC_INITIALIZER_END
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) { inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) {
if (!p || !class_name || !member_name || !accessValueFunctions) return PIByteArray(); if (!p || !class_name || !member_name) return PIByteArray();
AccessValueFunction af = accessValueFunctions->value(class_name, (AccessValueFunction)0); AccessValueFunction af = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction)0);
if (!af) return PIByteArray(); if (!af) return PIByteArray();
return af(p, member_name); return af(p, member_name);
} }
inline const char * getMemberType(const char * class_name, const char * member_name) { inline const char * getMemberType(const char * class_name, const char * member_name) {
if (!class_name || !member_name || !accessTypeFunctions) return ""; if (!class_name || !member_name) return "";
AccessTypeFunction af = accessTypeFunctions->value(class_name, (AccessTypeFunction)0); AccessTypeFunction af = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction)0);
if (!af) return ""; if (!af) return "";
return af(member_name); return af(member_name);
} }
@@ -295,26 +378,14 @@ PIP_EXPORT PIVariant getMemberAsVariant(const void * p, const char * class_name,
template<typename T, typename std::enable_if<std::is_assignable<T &, const T &>::value, int>::type = 0> template<typename T, typename std::enable_if<std::is_assignable<T &, const T &>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) {ret << v;} void serialize(PIByteArray & ret, const T & v) {
ret << v;
}
template<typename T, typename std::enable_if<!std::is_assignable<T &, const T &>::value, int>::type = 0> template<typename T, typename std::enable_if<!std::is_assignable<T &, const T &>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) {} void serialize(PIByteArray & ret, const T & v) {}
} } // namespace PICodeInfo
class PIP_EXPORT __PICodeInfoInitializer__ {
public:
__PICodeInfoInitializer__() {
if (_inited_) return;
_inited_ = true;
PICodeInfo::classesInfo = new PIMap<PIConstChars, PICodeInfo::ClassInfo * >;
PICodeInfo::enumsInfo = new PIMap<PIConstChars, PICodeInfo::EnumInfo * >;
PICodeInfo::accessValueFunctions = new PIMap<PIConstChars, PICodeInfo::AccessValueFunction>;
PICodeInfo::accessTypeFunctions = new PIMap<PIConstChars, PICodeInfo::AccessTypeFunction>;
}
static bool _inited_;
};
static __PICodeInfoInitializer__ __picodeinfoinitializer__;
#endif // PICODEINFO_H #endif // PICODEINFO_H

View File

@@ -20,7 +20,6 @@
#include "picodeparser.h" #include "picodeparser.h"
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const { PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIStringList arg_vals; PIStringList arg_vals;
while (!args_.isEmpty()) { while (!args_.isEmpty()) {
@@ -32,17 +31,20 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIString ca; PIString ca;
if (bi >= 0 && bi < ci) { if (bi >= 0 && bi < ci) {
ca = args_.left(args_.takeLeft(bi).toInt()); ca = args_.left(args_.takeLeft(bi).toInt());
ci -= ca.size_s(); bi -= ca.size_s(); ci -= ca.size_s();
bi -= ca.size_s();
ca += '(' + args_.takeRange('(', ')') + ')'; ca += '(' + args_.takeRange('(', ')') + ')';
} else { } else {
ca = args_.takeLeft(ci); ca = args_.takeLeft(ci);
} }
arg_vals << ca; arg_vals << ca;
args_.trim(); args_.takeLeft(1); args_.trim(); args_.trim();
args_.takeLeft(1);
args_.trim();
} }
if (args.size() != arg_vals.size()) { if (args.size() != arg_vals.size()) {
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect") piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect") << args.size() << "arguments but takes"
<< args.size() << "arguments but takes" << arg_vals.size() << "!"; << arg_vals.size() << "!";
if (ok != 0) *ok = false; if (ok != 0) *ok = false;
return PIString(); return PIString();
} }
@@ -72,7 +74,6 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
} }
PICodeParser::PICodeParser() { PICodeParser::PICodeParser() {
macros_iter = 32; macros_iter = 32;
with_includes = true; with_includes = true;
@@ -85,63 +86,67 @@ void PICodeParser::parseFile(const PIString & file, bool follow_includes) {
clear(); clear();
parseFileInternal(file, follow_includes); parseFileInternal(file, follow_includes);
/*piCout << "\n\n"; /*piCout << "\n\n";
piForeachC (Entity * c, entities) { for (const auto * c: entities) {
piCout << ""; piCout << "";
piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta; piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta;
if (c->parent_scope) if (c->parent_scope)
piCout << "parent" << c->parent_scope->name; piCout << "parent" << c->parent_scope->name;
piCout << "Functions:"; piCout << "Functions:";
piForeachC (Member & m, c->functions) for (const auto & m: c->functions)
piCout << m.type << m.name << m.meta; piCout << m.type << m.name << m.meta;
piCout << "Members:"; piCout << "Members:";
piForeachC (Member & m, c->members) for (const auto & m: c->members)
piCout << m.type << m.name << m.meta; piCout << m.type << m.name << m.meta;
} }
piCout << "\n\nDefines:"; piCout << "\n\nDefines:";
piForeachC (Define & m, defines) for (const auto & m: defines)
piCout << PIStringAscii("define") << m.first << m.second; piCout << PIStringAscii("define") << m.first << m.second;
piCout << "\n\nMacros:"; piCout << "\n\nMacros:";
piForeachC (Macro & m, macros) for (const auto & m: macros)
piCout << "Macro:" << m.name << m.args << m.value; piCout << "Macro:" << m.name << m.args << m.value;
piCout << "\n\nClasses:"; piCout << "\n\nClasses:";
piCout << "\n\nEnums:"; piCout << "\n\nEnums:";
piForeachC (Enum & c, enums) { for (const auto & c: enums) {
piCout << PIStringAscii("enum") << c.name << c.meta; piCout << PIStringAscii("enum") << c.name << c.meta;
piForeachC (EnumeratorInfo & e, c.members) for (const auto & e: c.members)
piCout << " " << e.name << '=' << e.value << e.meta; piCout << " " << e.name << '=' << e.value << e.meta;
} }
piCout << "\n\nTypedefs:"; piCout << "\n\nTypedefs:";
piForeachC (Typedef & c, typedefs) for (const auto & c: typedefs)
piCout << PIStringAscii("typedef") << c;*/ piCout << PIStringAscii("typedef") << c;*/
} }
void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) { void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) {
clear(); clear();
piForeachC (PIString & f, files) for (const auto & f: files)
parseFileInternal(f, follow_includes); parseFileInternal(f, follow_includes);
/*piCout << "\n\nDefines:"; /*piCout << "\n\nDefines:";
piForeachC (Define & m, defines) for (const auto & m: defines)
piCout << PIStringAscii("define") << m.first << m.second; piCout << PIStringAscii("define") << m.first << m.second;
piCout << "\n\nMacros:"; piCout << "\n\nMacros:";
piForeachC (Macro & m, macros) for (const auto & m: macros)
piCout << "Macro:" << m.name << m.args << m.value; piCout << "Macro:" << m.name << m.args << m.value;
piCout << "\n\nClasses:"; piCout << "\n\nClasses:";
piForeachC (Entity * c, entities) for (const auto * c: entities)
piCout << PIStringAscii("class") << c->name << c->parents; piCout << PIStringAscii("class") << c->name << c->parents;
piCout << "\n\nEnums:"; piCout << "\n\nEnums:";
piForeachC (Enum & c, enums) for (const auto & c: enums)
piCout << PIStringAscii("enum") << c.name << c.members; piCout << PIStringAscii("enum") << c.name << c.members;
piCout << "\n\nTypedefs:"; piCout << "\n\nTypedefs:";
piForeachC (Typedef & c, typedefs) for (const auto & c: typedefs)
piCout << PIStringAscii("typedef") << c;*/ piCout << PIStringAscii("typedef") << c;*/
} }
void PICodeParser::parseFileContent(PIString fc) {
parseFileContent(fc, false);
}
bool PICodeParser::isEnum(const PIString & name) { bool PICodeParser::isEnum(const PIString & name) {
piForeachC (Enum & e, enums) for (const auto & e: enums)
if (e.name == name) if (e.name == name) return true;
return true;
return false; return false;
} }
@@ -174,7 +179,8 @@ bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes
void PICodeParser::clear() { void PICodeParser::clear() {
piForeach (Entity * i, entities) delete i; for (auto * i: entities)
delete i;
defines.clear(); defines.clear();
macros.clear(); macros.clear();
enums.clear(); enums.clear();
@@ -187,37 +193,142 @@ void PICodeParser::clear() {
cur_def_vis = Global; cur_def_vis = Global;
anon_num = 0; anon_num = 0;
PIStringList defs = PIStringAscii(PICODE_DEFINES).split(","); PIStringList defs = PIStringAscii(PICODE_DEFINES).split(",");
piForeachC (PIString & d, defs) for (const auto & d: defs)
defines << Define(d, ""); defines << Define(d, "");
defines << Define(PIStringAscii("PICODE"), "") << custom_defines; defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name") macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent") << Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent")
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"), "", PIStringList() << "name" << "parent") << Macro(PIStringAscii("PIOBJECT_SUBCLASS"),
"",
PIStringList() << "name"
<< "parent")
<< Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name") << Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name")
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name") << Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name") << Macro(PIStringAscii("PRIVATE_DECLARATION"))
<< Macro(PIStringAscii("PRIVATE_DECLARATION"))
<< Macro(PIStringAscii("EVENT"), "void name();", PIStringList() << "name") << Macro(PIStringAscii("EVENT"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name") << Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT1"), "void name(a0 n0);", PIStringList() << "name" << "a0" << "n0") << Macro(PIStringAscii("EVENT1"),
<< Macro(PIStringAscii("EVENT2"), "void name(a0 n0, a1 n1);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1") "void name(a0 n0);",
<< Macro(PIStringAscii("EVENT3"), "void name(a0 n0, a1 n1, a2 n2);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2") PIStringList() << "name"
<< Macro(PIStringAscii("EVENT4"), "void name(a0 n0, a1 n1, a2 n2, a3 n3);", PIStringList() << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3") << "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT2"),
"void name(a0 n0, a1 n1);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT3"),
"void name(a0 n0, a1 n1, a2 n2);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT4"),
"void name(a0 n0, a1 n1, a2 n2, a3 n3);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3")
<< Macro(PIStringAscii("EVENT_HANDLER" ), "ret name()", PIStringList() << "ret" << "name") << Macro(PIStringAscii("EVENT_HANDLER"),
<< Macro(PIStringAscii("EVENT_HANDLER0"), "ret name()", PIStringList() << "ret" << "name") "ret name()",
<< Macro(PIStringAscii("EVENT_HANDLER1"), "ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0") PIStringList() << "ret"
<< Macro(PIStringAscii("EVENT_HANDLER2"), "ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1") << "name")
<< Macro(PIStringAscii("EVENT_HANDLER3"), "ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2") << Macro(PIStringAscii("EVENT_HANDLER0"),
<< Macro(PIStringAscii("EVENT_HANDLER4"), "ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3") "ret name()",
PIStringList() << "ret"
<< "name")
<< Macro(PIStringAscii("EVENT_HANDLER1"),
"ret name(a0 n0)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT_HANDLER2"),
"ret name(a0 n0, a1 n1)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT_HANDLER3"),
"ret name(a0 n0, a1 n1, a2 n2)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT_HANDLER4"),
"ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3")
<< Macro(PIStringAscii("EVENT_VHANDLER" ), "virtual ret name()", PIStringList() << "ret" << "name") << Macro(PIStringAscii("EVENT_VHANDLER"),
<< Macro(PIStringAscii("EVENT_VHANDLER0"), "virtual ret name()", PIStringList() << "ret" << "name") "virtual ret name()",
<< Macro(PIStringAscii("EVENT_VHANDLER1"), "virtual ret name(a0 n0)", PIStringList() << "ret" << "name" << "a0" << "n0") PIStringList() << "ret"
<< Macro(PIStringAscii("EVENT_VHANDLER2"), "virtual ret name(a0 n0, a1 n1)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1") << "name")
<< Macro(PIStringAscii("EVENT_VHANDLER3"), "virtual ret name(a0 n0, a1 n1, a2 n2)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2") << Macro(PIStringAscii("EVENT_VHANDLER0"),
<< Macro(PIStringAscii("EVENT_VHANDLER4"), "virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)", PIStringList() << "ret" << "name" << "a0" << "n0" << "a1" << "n1" << "a2" << "n2" << "a3" << "n3") "virtual ret name()",
; PIStringList() << "ret"
<< "name")
<< Macro(PIStringAscii("EVENT_VHANDLER1"),
"virtual ret name(a0 n0)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT_VHANDLER2"),
"virtual ret name(a0 n0, a1 n1)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT_VHANDLER3"),
"virtual ret name(a0 n0, a1 n1, a2 n2)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT_VHANDLER4"),
"virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3");
} }
@@ -232,6 +343,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
static const PIString s_typedef = PIStringAscii("typedef"); static const PIString s_typedef = PIStringAscii("typedef");
static const PIString s_namespace = PIStringAscii("namespace"); static const PIString s_namespace = PIStringAscii("namespace");
static const PIString s_template = PIStringAscii("template"); static const PIString s_template = PIStringAscii("template");
static const PIString s_L = PIStringAscii("$L");
bool mlc = false, cc = false; bool mlc = false, cc = false;
int mls = 0, ole = -1, /*ccs = 0,*/ end = 0; int mls = 0, ole = -1, /*ccs = 0,*/ end = 0;
@@ -247,22 +359,40 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (i > 0) pc = c; if (i > 0) pc = c;
c = fc[i].toAscii(); c = fc[i].toAscii();
if (c == '"' && !mlc && pc != '\'') { if (c == '"' && !mlc && pc != '\'') {
if (i > 0) if (fc[i - 1] == '\\') continue; if (i > 0)
if (fc[i - 1] == '\\') continue;
cc = !cc; cc = !cc;
continue; continue;
} }
if (i > 0) if (i > 0)
if (c == '\\' && fc[i - 1].toAscii() != '\\') { if (c == '\\' && fc[i - 1].toAscii() != '\\') {
fc.cutMid(i, 2); fc.cutMid(i, 1);
--i; fc.replace(i, 1, s_L);
++i;
continue; continue;
} }
if (cc) continue; if (cc) continue;
if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;} if (fc.mid(i, 2) == "/*") {
if (fc.mid(i, 2) == "*/" && mlc) {mlc = false; fc.cutMid(mls, i - mls + 2); i = mls - 1; continue;} mlc = true;
if (fc.mid(i, 2) == "//" && !mlc) {ole = fc.find('\n', i); fc.cutMid(i, ole < 0 ? -1 : ole - i); --i; continue;} mls = i;
++i;
continue;
}
if (fc.mid(i, 2) == "*/" && mlc) {
mlc = false;
fc.cutMid(mls, i - mls + 2);
i = mls - 1;
continue;
}
if (fc.mid(i, 2) == "//" && !mlc) {
ole = fc.find('\n', i);
fc.cutMid(i, ole < 0 ? -1 : ole - i);
--i;
continue;
}
} }
pfc = procMacros(fc); pfc = procMacros(fc);
pfc.removeAll(s_L);
if (main) return true; if (main) return true;
@@ -276,7 +406,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
} }
replaced_cnt++; replaced_cnt++;
replaced = false; replaced = false;
piForeachC (Define & d, defines) { for (const auto & d: defines) {
int ind(-1); int ind(-1);
while ((ind = pfc.find(d.first, ind + 1)) >= 0) { while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
PIChar pc, nc; PIChar pc, nc;
@@ -288,14 +418,15 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
replaced = true; replaced = true;
} }
} }
piForeachC (Macro & m, macros) { for (const auto & m: macros) {
int ind(-1); int ind(-1);
while ((ind = pfc.find(m.name, ind + 1)) >= 0) { while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
PIChar pc, nc; PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1]; if (ind > 0) pc = pfc[ind - 1];
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(), 1)[0]; if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(), 1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue; if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
PIString ret, range; bool ok(false); PIString ret, range;
bool ok(false);
range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')'); range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')');
ret = m.expand(range, &ok); ret = m.expand(range, &ok);
if (!ok) return false; if (!ok) return false;
@@ -311,6 +442,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
// piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc; // piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
int pl = -1; int pl = -1;
cur_def_vis = Global;
while (!pfc.isEmpty()) { while (!pfc.isEmpty()) {
pfc.trim(); pfc.trim();
int nl = pfc.size_s(); int nl = pfc.size_s();
@@ -321,6 +453,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
PIString prev_namespace = cur_namespace, ccmn; PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += pfc.takeCWord() + s_ns; cur_namespace += pfc.takeCWord() + s_ns;
ccmn = pfc.takeRange('{', '}'); ccmn = pfc.takeRange('{', '}');
// piCout << "namespace" << cur_namespace;
parseClass(0, ccmn, true); parseClass(0, ccmn, true);
cur_namespace = prev_namespace; cur_namespace = prev_namespace;
continue; continue;
@@ -330,14 +463,25 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
pfc.takeRange('<', '>'); pfc.takeRange('<', '>');
bool def = !isDeclaration(pfc, 0, &end); bool def = !isDeclaration(pfc, 0, &end);
pfc.cutLeft(end); pfc.cutLeft(end);
if (def) pfc.takeRange('{', '}'); if (def)
else pfc.takeSymbol(); pfc.takeRange('{', '}');
else
pfc.takeSymbol();
continue; continue;
} }
if (pfc.left(5) == s_class || pfc.left(6) == s_struct || pfc.left(5) == s_union) { if (pfc.left(5) == s_class || pfc.left(6) == s_struct || pfc.left(5) == s_union) {
int dind = pfc.find('{', 0), find = pfc.find(';', 0); int dind = pfc.find('{', 0), find = pfc.find(';', 0);
if (dind < 0 && find < 0) {pfc.cutLeft(6); continue;} // piCout << pfc.left(6) << dind << find;
if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;} if (dind < 0 && find < 0) {
pfc.cutLeft(6);
continue;
}
if (dind < 0 || find < dind) {
// piCout << "skip FC" << (find + 1) << pfc.left(find + 1);
pfc.cutLeft(find + 1);
// pfc.cutLeft(6);
continue;
}
ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc; ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
pfc.remove(0, ccmn.size()); pfc.remove(0, ccmn.size());
parseClass(0, ccmn, false); parseClass(0, ccmn, false);
@@ -348,6 +492,13 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
tmp = pfc.takeCWord(); tmp = pfc.takeCWord();
pfc.trim(); pfc.trim();
MetaMap meta = maybeMeta(pfc); MetaMap meta = maybeMeta(pfc);
if (tmp == s_class || tmp == s_struct) {
tmp = pfc.takeCWord();
pfc.trim();
MetaMap smeta = maybeMeta(pfc);
meta << smeta;
}
// piCout << "pfc E" << cur_namespace << "," << tmp;
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta); parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
pfc.takeSymbol(); pfc.takeSymbol();
continue; continue;
@@ -355,8 +506,10 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (pfc.left(7) == s_typedef) { if (pfc.left(7) == s_typedef) {
pfc.cutLeft(7); pfc.cutLeft(7);
typedefs << parseTypedef(pfc.takeLeft(pfc.find(';'))); typedefs << parseTypedef(pfc.takeLeft(pfc.find(';')));
if (typedefs.back().first.isEmpty()) typedefs.pop_back(); if (typedefs.back().first.isEmpty())
else root_.typedefs << typedefs.back(); typedefs.pop_back();
else
root_.typedefs << typedefs.back();
pfc.takeSymbol(); pfc.takeSymbol();
continue; continue;
} }
@@ -397,28 +550,34 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
PIStringList pl = cd.takeMid(ind + 1).trim().split(','); PIStringList pl = cd.takeMid(ind + 1).trim().split(',');
cd.cutRight(1); cd.cutRight(1);
Entity * pe = 0; Entity * pe = 0;
piForeachC (PIString & p, pl) { for (const auto & p: pl) {
if (p.contains(' ')) pn = p.mid(p.find(' ') + 1); if (p.contains(' '))
else pn = p; pn = p.mid(p.find(' ') + 1);
else
pn = p;
pe = findEntityByName(pn); pe = findEntityByName(pn);
if (pe == 0) ;//{piCout << "Error: can`t find" << pn;} if (pe == 0)
else parents << pe; ; //{piCout << "Error: can`t find" << pn;}
else
parents << pe;
} }
} }
PIString typename_ = cd.left(6).trim(); PIString typename_ = cd.left(6).trim();
bool is_class = typename_ == s_class; bool is_class = typename_ == s_class;
Visibility vis = cur_def_vis;
cur_def_vis = (is_class ? Private : Public); cur_def_vis = (is_class ? Private : Public);
PIString cn = cd.mid(6).trim(); PIString cn = cd.mid(6).trim();
bool has_name = !cn.isEmpty(); bool has_name = !cn.isEmpty();
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>'; if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
// piCout << "found " << typename_ << cn; // piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return 0; if (cn.isEmpty()) return nullptr;
Entity * e = new Entity(); Entity * e = new Entity();
e->meta = meta; e->meta = meta;
e->name = cur_namespace + cn; e->name = cur_namespace + cn;
e->type = typename_; e->type = typename_;
e->has_name = has_name; e->has_name = has_name;
e->parents = parents; e->parents = parents;
e->visibility = vis;
e->file = cur_file; e->file = cur_file;
entities << e; entities << e;
return e; return e;
@@ -441,10 +600,6 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
Visibility prev_vis = cur_def_vis; Visibility prev_vis = cur_def_vis;
int dind = fc.find('{'), find = fc.find(';'), end = 0; int dind = fc.find('{'), find = fc.find(';'), end = 0;
if (dind < 0 && find < 0) return; if (dind < 0 && find < 0) return;
if (dind < 0 || find < dind) {
fc.left(find);
return;
}
// piCout << "parse class <****\n" << fc << "\n****>"; // piCout << "parse class <****\n" << fc << "\n****>";
Entity * ce = parent; Entity * ce = parent;
if (!is_namespace) { if (!is_namespace) {
@@ -452,7 +607,6 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
fc.trim().cutLeft(1).cutRight(1).trim(); fc.trim().cutLeft(1).cutRight(1).trim();
} }
// piCout << "found class <****\n" << fc << "\n****>"; // piCout << "found class <****\n" << fc << "\n****>";
///if (!ce) return PIString();
if (ce) { if (ce) {
if (parent) parent->children << ce; if (parent) parent->children << ce;
ce->parent_scope = parent; ce->parent_scope = parent;
@@ -460,15 +614,27 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
int ps = -1; int ps = -1;
bool def = false; bool def = false;
PIString prev_namespace = cur_namespace, stmp; PIString prev_namespace = cur_namespace, stmp;
if (ce) cur_namespace += ce->name + s_ns; if (ce) cur_namespace = ce->name + s_ns;
//piCout << "parse class" << ce->name << "namespace" << cur_namespace; // piCout << "parse class" << (ce ? ce->name : "NULL") << "namespace" << cur_namespace;
// piCout << "\nparse class" << ce->name << "namespace" << cur_namespace; // piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
PIString cw = fc.takeCWord(), tmp; PIString cw = fc.takeCWord(), tmp;
// piCout << "\ntaked word" << cw; // piCout << "\ntaked word" << cw;
if (cw == s_public ) {cur_def_vis = Public; fc.cutLeft(1); continue;} if (cw == s_public) {
if (cw == s_protected) {cur_def_vis = Protected; fc.cutLeft(1); continue;} cur_def_vis = Public;
if (cw == s_private ) {cur_def_vis = Private; fc.cutLeft(1); continue;} fc.cutLeft(1);
continue;
}
if (cw == s_protected) {
cur_def_vis = Protected;
fc.cutLeft(1);
continue;
}
if (cw == s_private) {
cur_def_vis = Private;
fc.cutLeft(1);
continue;
}
if (cw == s_namespace) { if (cw == s_namespace) {
PIString prev_namespace = cur_namespace, ccmn; PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += fc.takeCWord() + s_ns; cur_namespace += fc.takeCWord() + s_ns;
@@ -478,6 +644,7 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
continue; continue;
} }
if (cw == s_class || cw == s_struct || cw == s_union) { if (cw == s_class || cw == s_struct || cw == s_union) {
// piCout << cw << isDeclaration(fc, 0, &end);
if (isDeclaration(fc, 0, &end)) { if (isDeclaration(fc, 0, &end)) {
fc.cutLeft(end); fc.cutLeft(end);
fc.takeSymbol(); fc.takeSymbol();
@@ -494,18 +661,27 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
tmp = fc.takeCWord(); tmp = fc.takeCWord();
fc.trim(); fc.trim();
MetaMap meta = maybeMeta(fc); MetaMap meta = maybeMeta(fc);
if (tmp == s_class || tmp == s_struct) {
tmp = fc.takeCWord();
fc.trim();
MetaMap smeta = maybeMeta(fc);
meta << smeta;
}
// piCout << "pc E" << cur_namespace << "," << tmp;
parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta); parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
fc.takeSymbol(); fc.takeSymbol();
continue; continue;
} }
if (cw == s_friend) {fc.cutLeft(fc.find(';') + 1); continue;} if (cw == s_friend) {
fc.cutLeft(fc.find(';') + 1);
continue;
}
if (cw == s_typedef) { if (cw == s_typedef) {
if (ce) { if (ce) {
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';'))); ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
typedefs << ce->typedefs.back(); typedefs << ce->typedefs.back();
typedefs.back().first.insert(0, cur_namespace); typedefs.back().first.insert(0, cur_namespace);
if (ce->typedefs.back().first.isEmpty()) if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back();
ce->typedefs.pop_back();
} }
fc.takeSymbol(); fc.takeSymbol();
continue; continue;
@@ -514,17 +690,22 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
fc.takeRange('<', '>'); fc.takeRange('<', '>');
def = !isDeclaration(fc, 0, &end); def = !isDeclaration(fc, 0, &end);
fc.cutLeft(end); fc.cutLeft(end);
if (def) fc.takeRange('{', '}'); if (def)
else fc.takeSymbol(); fc.takeRange('{', '}');
else
fc.takeSymbol();
continue; continue;
} }
def = !isDeclaration(fc, 0, &end); def = !isDeclaration(fc, 0, &end);
tmp = (cw + fc.takeLeft(end)).trim(); tmp = (cw + fc.takeLeft(end)).trim();
if (!tmp.isEmpty() && ce) if (!tmp.isEmpty() && ce) parseMember(ce, tmp);
parseMember(ce, tmp); if (def)
if (def) fc.takeRange('{', '}'); fc.takeRange('{', '}');
else fc.takeSymbol(); else
if (ps == fc.size_s()) {fc.cutLeft(1);} fc.takeSymbol();
if (ps == fc.size_s()) {
fc.cutLeft(1);
}
ps = fc.size_s(); ps = fc.size_s();
} }
cur_def_vis = prev_vis; cur_def_vis = prev_vis;
@@ -536,7 +717,7 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
PICodeParser::MetaMap ret; PICodeParser::MetaMap ret;
if (fc.isEmpty()) return ret; if (fc.isEmpty()) return ret;
PIStringList ml = fc.split(','); PIStringList ml = fc.split(',');
piForeachC (PIString & m, ml) { for (const auto & m: ml) {
int i = m.find('='); int i = m.find('=');
if (i < 0) { if (i < 0) {
ret[m.trimmed()] = PIString(); ret[m.trimmed()] = PIString();
@@ -561,21 +742,24 @@ bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc
PIStringList vl(fc.split(',')); PIStringList vl(fc.split(','));
PIString vn; PIString vn;
int cv = -1, ind = 0; int cv = -1, ind = 0;
piForeach (PIString & v, vl) { for (auto & v: vl) {
MetaMap meta; MetaMap meta;
int mi = v.find(s_M); int mi = v.find(s_M);
if (mi >= 0) { if (mi >= 0) {
meta = tmp_meta.value(v.takeMid(mi, 5)); meta = tmp_meta.value(v.takeMid(mi, 5));
v.replaceAll(s_ss, ' '); v.replaceAll(s_ss, ' ');
} }
vn = v; ind = v.find('='); vn = v;
if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);} ind = v.find('=');
if (ind > 0) {
cv = v.right(v.size_s() - ind - 1).toInt();
vn = v.left(ind);
}
if (ind < 0) ++cv; if (ind < 0) ++cv;
e.members << EnumeratorInfo(vn.trim(), cv, meta); e.members << EnumeratorInfo(vn.trim(), cv, meta);
} }
if (!e.members.isEmpty()) if (!e.members.isEmpty())
if (e.members.back().name.isEmpty()) if (e.members.back().name.isEmpty()) e.members.pop_back();
e.members.pop_back();
enums << e; enums << e;
return true; return true;
} }
@@ -589,7 +773,10 @@ PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
if (fc.contains('(')) { if (fc.contains('(')) {
int start = fc.find('('), end = fc.find(')'); int start = fc.find('('), end = fc.find(')');
td.first = fc.takeMid(start + 1, end - start - 1).trim(); td.first = fc.takeMid(start + 1, end - start - 1).trim();
if (td.first.left(1) == PIChar('*')) {td.first.cutLeft(1).trim(); fc.insert(start + 1, '*');} if (td.first.left(1) == PIChar('*')) {
td.first.cutLeft(1).trim();
fc.insert(start + 1, '*');
}
td.second = fc.trim(); td.second = fc.trim();
} else { } else {
td.first = fc.takeMid(fc.findLast(' ')).trim(); td.first = fc.takeMid(fc.findLast(' ')).trim();
@@ -636,7 +823,11 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
PIString ctemp, crepl; PIString ctemp, crepl;
while (ts >= 0) { while (ts >= 0) {
ctemp = fc.mid(ts).takeRange('<', '>'); ctemp = fc.mid(ts).takeRange('<', '>');
if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find('<', te); continue;} if (ctemp.isEmpty()) {
te = ts + 1;
ts = fc.find('<', te);
continue;
}
crepl = s_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); fc.replace(ts, ctemp.size_s() + 2, crepl);
tmp_temp[crepl] = '<' + ctemp + '>'; tmp_temp[crepl] = '<' + ctemp + '>';
@@ -681,19 +872,17 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
normalizeEntityNamespace(me.type); normalizeEntityNamespace(me.type);
int i = 0; int i = 0;
// piCout << me.arguments_full; // piCout << me.arguments_full;
piForeach (PIString & a, me.arguments_full) for (auto & a: me.arguments_full)
if ((i = a.find('=')) > 0) if ((i = a.find('=')) > 0) a.cutRight(a.size_s() - i).trim();
a.cutRight(a.size_s() - i).trim();
for (int j = 0; j < me.arguments_full.size_s(); ++j) for (int j = 0; j < me.arguments_full.size_s(); ++j)
if (me.arguments_full[j] == s_void) { if (me.arguments_full[j] == s_void) {
me.arguments_full.remove(j); me.arguments_full.remove(j);
--j; --j;
} }
me.arguments_type = me.arguments_full; me.arguments_type = me.arguments_full;
piForeach (PIString & a, me.arguments_type) { for (auto & a: me.arguments_type) {
crepl.clear(); crepl.clear();
if (a.contains('[')) if (a.contains('[')) crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
for (ts = a.size_s() - 1; ts >= 0; --ts) for (ts = a.size_s() - 1; ts >= 0; --ts)
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break; if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
a.cutRight(a.size_s() - ts - 1); a.cutRight(a.size_s() - ts - 1);
@@ -713,7 +902,7 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
// piCout << "member" << fc << tl; // piCout << "member" << fc << tl;
// piCout << "member after eb" << fc << ", bits =" << bits; // piCout << "member after eb" << fc << ", bits =" << bits;
if (tl.isEmpty()) return true; if (tl.isEmpty()) return true;
piForeach (PIString & v, tl) for (auto & v: tl)
removeAssignment(v); removeAssignment(v);
bool vn = true; bool vn = true;
ctemp = tl.front().trim(); ctemp = tl.front().trim();
@@ -723,8 +912,11 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
ctemp.trim(); ctemp.trim();
} }
for (ts = ctemp.size_s() - 1; ts > 0; --ts) { for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;} if (vn) {
else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;} if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;
} else {
if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;
}
} }
me.type = ctemp.takeLeft(ts + 1); me.type = ctemp.takeLeft(ts + 1);
me.visibility = cur_def_vis; me.visibility = cur_def_vis;
@@ -755,20 +947,20 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
normalizeEntityNamespace(type); normalizeEntityNamespace(type);
tl[0] = ctemp.trim(); tl[0] = ctemp.trim();
// piCout << "vars" << tl; // piCout << "vars" << tl;
piForeachC (PIString & v, tl) { for (const auto & v: tl) {
crepl.clear(); crepl.clear();
me.name = v.trimmed(); me.name = v.trimmed();
me.type = type; me.type = type;
restoreTmpMeta(&me); restoreTmpMeta(&me);
if (me.name.isEmpty()) continue; if (me.name.isEmpty()) continue;
if (me.name.contains('[')) if (me.name.contains('[')) crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
while (!me.name.isEmpty()) { while (!me.name.isEmpty()) {
if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) { if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) {
me.type += me.name.takeLeft(1); me.type += me.name.takeLeft(1);
me.name.trim(); me.name.trim();
} else break; } else
break;
} }
me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*')); me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*'));
me.type += crepl; me.type += crepl;
@@ -815,13 +1007,25 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
break; break;
} }
n.push_front(' '); n.push_front(' ');
if (n.find(s_s_const_s) >= 0) {n.replaceAll(s_s_const_s, ""); pref += s_const_s;} if (n.find(s_s_const_s) >= 0) {
if (n.find(s_s_static_s) >= 0) {n.replaceAll(s_s_static_s, ""); pref += s_static_s;} n.replaceAll(s_s_const_s, "");
if (n.find(s_s_mutable_s) >= 0) {n.replaceAll(s_s_mutable_s, ""); pref += s_mutable_s;} pref += s_const_s;
if (n.find(s_s_volatile_s) >= 0) {n.replaceAll(s_s_volatile_s, ""); pref += s_volatile_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(); n.trim();
int f = 0; int f = 0;
piForeachC (Entity * e, entities) { for (const auto * e: entities) {
if (e->name == n) { if (e->name == n) {
n = (pref + n + suff).trim(); n = (pref + n + suff).trim();
return; return;
@@ -833,7 +1037,7 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
return; return;
} }
} }
piForeachC (Enum & e, enums) { for (const auto & e: enums) {
if ((f = e.name.find(n)) >= 0) if ((f = e.name.find(n)) >= 0)
if (e.name.at(f - 1) == PIChar(':')) if (e.name.at(f - 1) == PIChar(':'))
if (e.name.find(cur_namespace) >= 0) { if (e.name.find(cur_namespace) >= 0) {
@@ -842,7 +1046,7 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
return; return;
} }
} }
piForeachC (Typedef & e, typedefs) { for (const auto & e: typedefs) {
if ((f = e.first.find(n)) >= 0) if ((f = e.first.find(n)) >= 0)
if (e.first.at(f - 1) == PIChar(':')) if (e.first.at(f - 1) == PIChar(':'))
if (e.first.find(cur_namespace) >= 0) { if (e.first.find(cur_namespace) >= 0) {
@@ -858,11 +1062,11 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
void PICodeParser::restoreTmpTemp(Member * e) { void PICodeParser::restoreTmpTemp(Member * e) {
static const PIString s_T = PIStringAscii("$T"); static const PIString s_T = PIStringAscii("$T");
int i = 0; int i = 0;
piForeach (PIString & a, e->arguments_full) { for (auto & a: e->arguments_full) {
while ((i = a.find(s_T)) >= 0) while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]); a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
} }
piForeach (PIString & a, e->arguments_type) { for (auto & a: e->arguments_type) {
while ((i = a.find(s_T)) >= 0) while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]); a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
} }
@@ -918,10 +1122,25 @@ double PICodeParser::procMacrosCond(PIString fc) {
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
cc = fc[0].toAscii(); cc = fc[0].toAscii();
nc = (fc.size() > 1 ? fc[1].toAscii() : 0); nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
if (cc == '!') {neg = true; fc.pop_front(); continue;} if (cc == '!') {
if (cc == '(') {br = true; brv = procMacrosCond(fc.takeRange('(', ')'));} neg = true;
if (cc == '&' && nc == '&') {fc.remove(0, 2); oper = 1; continue;} fc.pop_front();
if (cc == '|' && nc == '|') {fc.remove(0, 2); oper = 2; continue;} continue;
}
if (cc == '(') {
br = true;
brv = procMacrosCond(fc.takeRange('(', ')'));
}
if (cc == '&' && nc == '&') {
fc.remove(0, 2);
oper = 1;
continue;
}
if (cc == '|' && nc == '|') {
fc.remove(0, 2);
oper = 2;
continue;
}
if (!br) { if (!br) {
ce = fc.takeCWord(); ce = fc.takeCWord();
if (ce.isEmpty()) ce = fc.takeNumber(); if (ce.isEmpty()) ce = fc.takeNumber();
@@ -948,18 +1167,16 @@ double PICodeParser::procMacrosCond(PIString fc) {
bool PICodeParser::isDefineExists(const PIString & dn) { bool PICodeParser::isDefineExists(const PIString & dn) {
piForeachC (Define & d, defines) { for (const auto & d: defines) {
if (d.first == dn) if (d.first == dn) return true;
return true;
} }
return false; return false;
} }
double PICodeParser::defineValue(const PIString & dn) { double PICodeParser::defineValue(const PIString & dn) {
piForeachC (Define & d, defines) { for (const auto & d: defines) {
if (d.first == dn) if (d.first == dn) return d.second.isEmpty() ? 1. : d.second.toDouble();
return d.second.isEmpty() ? 1. : d.second.toDouble();
} }
return dn.toDouble(); return dn.toDouble();
} }
@@ -986,9 +1203,8 @@ void PICodeParser::replaceMeta(PIString & dn) {
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) { PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
piForeach (Entity * e, entities) for (auto * e: entities)
if (e->name == en) if (e->name == en) return e;
return e;
return 0; return 0;
} }
@@ -996,8 +1212,14 @@ PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) { bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
int dind = fc.find('{', start), find = fc.find(';', start); int dind = fc.find('{', start), find = fc.find(';', start);
// piCout << "isDeclaration" << dind << find << fc.left(10); // piCout << "isDeclaration" << dind << find << fc.left(10);
if (dind < 0 && find < 0) {if (end) *end = -1; return true;} if (dind < 0 && find < 0) {
if (dind < 0 || find < dind) {if (end) *end = find; return true;} if (end) *end = -1;
return true;
}
if (dind < 0 || find < dind) {
if (end) *end = find;
return true;
}
if (end) *end = dind; if (end) *end = dind;
return false; return false;
} }
@@ -1031,6 +1253,7 @@ PIString PICodeParser::procMacros(PIString fc) {
static const PIString s_elif = PIStringAscii("elif"); static const PIString s_elif = PIStringAscii("elif");
static const PIString s_else = PIStringAscii("else"); static const PIString s_else = PIStringAscii("else");
static const PIString s_endif = PIStringAscii("endif"); static const PIString s_endif = PIStringAscii("endif");
static const PIString s_L = PIStringAscii("$L");
if (fc.isEmpty()) return PIString(); if (fc.isEmpty()) return PIString();
int ifcnt = 0; int ifcnt = 0;
bool grab = false, skip = false, cond_ok = false; bool grab = false, skip = false, cond_ok = false;
@@ -1047,7 +1270,8 @@ PIString PICodeParser::procMacros(PIString fc) {
if (skip || grab) { if (skip || grab) {
if (mif.left(2) == s_if) ifcnt++; if (mif.left(2) == s_if) ifcnt++;
if (mif.left(5) == s_endif) { if (mif.left(5) == s_endif) {
if (ifcnt > 0) ifcnt--; if (ifcnt > 0)
ifcnt--;
else { else {
// piCout << "main endif" << skip << grab; // piCout << "main endif" << skip << grab;
if (grab) pfc += procMacros(nfc); if (grab) pfc += procMacros(nfc);
@@ -1060,7 +1284,8 @@ PIString PICodeParser::procMacros(PIString fc) {
if (cond_ok) { if (cond_ok) {
if (grab) { if (grab) {
pfc += procMacros(nfc); pfc += procMacros(nfc);
skip = true; grab = false; skip = true;
grab = false;
} }
continue; continue;
} }
@@ -1068,7 +1293,8 @@ PIString PICodeParser::procMacros(PIString fc) {
// piCout << "check elif" << skip << grab << cond_ok; // piCout << "check elif" << skip << grab << cond_ok;
if (!macroCondition(mif, mifcond.trimmed())) continue; if (!macroCondition(mif, mifcond.trimmed())) continue;
// piCout << "check elif ok"; // piCout << "check elif ok";
skip = false; grab = cond_ok = true; skip = false;
grab = cond_ok = true;
continue; continue;
} }
continue; continue;
@@ -1076,8 +1302,13 @@ PIString PICodeParser::procMacros(PIString fc) {
if (mif.left(4) == s_else && ifcnt == 0) { if (mif.left(4) == s_else && ifcnt == 0) {
// piCout << "main else" << skip << grab; // piCout << "main else" << skip << grab;
if (grab) pfc += procMacros(nfc); if (grab) pfc += procMacros(nfc);
if (skip && !cond_ok) {skip = false; grab = true;} if (skip && !cond_ok) {
else {skip = true; grab = false;} skip = false;
grab = true;
} else {
skip = true;
grab = false;
}
continue; continue;
} }
if (grab) nfc += line + '\n'; if (grab) nfc += line + '\n';
@@ -1086,8 +1317,10 @@ PIString PICodeParser::procMacros(PIString fc) {
if (mif.left(2) == s_if) { if (mif.left(2) == s_if) {
// piCout << "main if"; // piCout << "main if";
skip = grab = cond_ok = false; skip = grab = cond_ok = false;
if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true; if (macroCondition(mif, mifcond.trimmed()))
else skip = true; grab = cond_ok = true;
else
skip = true;
ifcnt = 0; ifcnt = 0;
nfc.clear(); nfc.clear();
} else { } else {
@@ -1095,8 +1328,10 @@ PIString PICodeParser::procMacros(PIString fc) {
// return false; /// WARNING: now skip errors // return false; /// WARNING: now skip errors
} }
} else { } else {
if (grab) nfc += line + '\n'; if (grab)
else if (!skip) pfc += line + '\n'; nfc += line + '\n';
else if (!skip)
pfc += line + '\n';
} }
} }
return pfc; return pfc;
@@ -1108,7 +1343,9 @@ bool PICodeParser::parseDirective(PIString d) {
static const PIString s_define = PIStringAscii("define"); static const PIString s_define = PIStringAscii("define");
static const PIString s_undef = PIStringAscii("undef"); static const PIString s_undef = PIStringAscii("undef");
static const PIString s_PIMETA = PIStringAscii("PIMETA"); static const PIString s_PIMETA = PIStringAscii("PIMETA");
static const PIString s_L = PIStringAscii("$L");
if (d.isEmpty()) return true; if (d.isEmpty()) return true;
d.replaceAll(s_L, '\n');
PIString dname = d.takeCWord(); PIString dname = d.takeCWord();
// piCout << "parseDirective" << d; // piCout << "parseDirective" << d;
if (dname == s_include) { if (dname == s_include) {
@@ -1147,7 +1384,10 @@ bool PICodeParser::parseDirective(PIString d) {
if (dname == s_undef) { if (dname == s_undef) {
PIString mname = d.takeCWord(); PIString mname = d.takeCWord();
for (int i = 0; i < defines.size_s(); ++i) for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) {defines.remove(i); --i;} if (defines[i].first == mname) {
defines.remove(i);
--i;
}
return true; return true;
} }
return true; return true;

View File

@@ -26,17 +26,27 @@
#ifndef PICODEPARSER_H #ifndef PICODEPARSER_H
#define PICODEPARSER_H #define PICODEPARSER_H
#include "pifile.h"
#include "pievaluator.h" #include "pievaluator.h"
#include "pifile.h"
inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));} inline bool _isCChar(const PIChar & c) {
inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);} return (c.isAlpha() || (c.toAscii() == '_'));
}
inline bool _isCChar(const PIString & c) {
if (c.isEmpty()) return false;
return _isCChar(c[0]);
}
class PIP_EXPORT PICodeParser { class PIP_EXPORT PICodeParser {
public: public:
PICodeParser(); PICodeParser();
enum Visibility {Global, Public, Protected, Private}; enum Visibility {
Global,
Public,
Protected,
Private
};
enum Attribute { enum Attribute {
NoAttributes = 0x0, NoAttributes = 0x0,
Const = 0x01, Const = 0x01,
@@ -110,16 +120,18 @@ public:
}; };
struct PIP_EXPORT EnumeratorInfo { struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {name = n; value = v; meta = m;} EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {
name = n;
value = v;
meta = m;
}
MetaMap meta; MetaMap meta;
PIString name; PIString name;
int value; int value;
}; };
struct PIP_EXPORT Enum { struct PIP_EXPORT Enum {
Enum(const PIString & n = PIString()) { Enum(const PIString & n = PIString()) { name = n; }
name = n;
}
MetaMap meta; MetaMap meta;
PIString name; PIString name;
PIVector<EnumeratorInfo> members; PIVector<EnumeratorInfo> members;
@@ -127,6 +139,7 @@ public:
void parseFile(const PIString & file, bool follow_includes = true); void parseFile(const PIString & file, bool follow_includes = true);
void parseFiles(const PIStringList & files, bool follow_includes = true); void parseFiles(const PIStringList & files, bool follow_includes = true);
void parseFileContent(PIString fc);
void includeDirectory(const PIString & dir) { includes << dir; } void includeDirectory(const PIString & dir) { includes << dir; }
void addDefine(const PIString & def_name, const PIString & def_value) { custom_defines << Define(def_name, def_value); } void addDefine(const PIString & def_name, const PIString & def_value) { custom_defines << Define(def_name, def_value); }
@@ -181,7 +194,6 @@ private:
PIString cur_namespace; PIString cur_namespace;
PIMap<PIString, PIString> tmp_temp; PIMap<PIString, PIString> tmp_temp;
PIMap<PIString, MetaMap> tmp_meta; PIMap<PIString, MetaMap> tmp_meta;
}; };
#endif // PICODEPARSER_H #endif // PICODEPARSER_H

View File

@@ -58,8 +58,8 @@
#ifndef PICOMPRESS_H #ifndef PICOMPRESS_H
#define PICOMPRESS_H #define PICOMPRESS_H
#include "pip_compress_export.h"
#include "pibytearray.h" #include "pibytearray.h"
#include "pip_compress_export.h"
//! \~english Compress "ba" with compression level "level", return empty %PIByteArray if no compression supports //! \~english Compress "ba" with compression level "level", return empty %PIByteArray if no compression supports
//! \~russian Сжимает "ba" с уровнем сжатия "level", возвращает пустой %PIByteArray если нет поддержки //! \~russian Сжимает "ba" с уровнем сжатия "level", возвращает пустой %PIByteArray если нет поддержки

View File

@@ -16,14 +16,19 @@
You should have received a copy of the GNU Lesser General Public License 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "piincludes_p.h"
#include "pikbdlistener.h" #include "pikbdlistener.h"
#include "piincludes_p.h"
#include "piliterals.h"
#include "piwaitevent_p.h"
// clang-format off
#ifndef WINDOWS #ifndef WINDOWS
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h> # include <wingdi.h>
# include <wincon.h> # include <wincon.h>
#endif #endif
// clang-format on
/** \class PIKbdListener /** \class PIKbdListener
* \brief Keyboard console input listener * \brief Keyboard console input listener
@@ -119,8 +124,10 @@ const PIKbdListener::EscSeq PIKbdListener::esc_seq[] = {
{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
}; };
void setupTerminal(bool on) { void setupTerminal(bool on) {
printf("\e[?1000"); printf(on ? "h" : "l"); printf("\e[?1000");
printf("\e[?1002"); printf(on ? "h" : "l"); printf(on ? "h" : "l");
printf("\e[?1002");
printf(on ? "h" : "l");
fflush(0); fflush(0);
} }
#endif #endif
@@ -140,11 +147,12 @@ PRIVATE_DEFINITION_START(PIKbdListener)
int int
#endif #endif
ret; ret;
PIWaitEvent event;
PRIVATE_DEFINITION_END(PIKbdListener) PRIVATE_DEFINITION_END(PIKbdListener)
PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() { PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() {
setName("keyboard_listener"); setName("keyboard_listener"_a);
_object = this; _object = this;
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE); PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
@@ -153,18 +161,19 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread()
#else #else
tcgetattr(0, &PRIVATE->sterm); tcgetattr(0, &PRIVATE->sterm);
#endif #endif
is_active = true;
ret_func = slot; ret_func = slot;
kbddata_ = _d; kbddata_ = _d;
dbl_interval = 400; dbl_interval = 400;
PIKbdListener::exiting = exit_enabled = false; PRIVATE->event.create();
PIKbdListener::exiting = false;
if (startNow) start(); if (startNow) start();
} }
PIKbdListener::~PIKbdListener() { PIKbdListener::~PIKbdListener() {
terminate(); stop();
end(); if (!waitForFinish(100_ms)) terminate();
PRIVATE->event.destroy();
} }
@@ -211,11 +220,11 @@ PIKbdListener::MouseButtons getButtons(DWORD v) {
void PIKbdListener::readKeyboard() { void PIKbdListener::readKeyboard() {
ke.key = 0; ke.key = 0;
ke.modifiers = 0; ke.modifiers = 0;
memset(rc, 0, 8); char rc[8];
piZeroMemory(rc, 8);
#ifdef WINDOWS #ifdef WINDOWS
INPUT_RECORD ir; INPUT_RECORD ir;
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret)); ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
//piCout << ir.EventType;
switch (ir.EventType) { switch (ir.EventType) {
case KEY_EVENT: { case KEY_EVENT: {
KEY_EVENT_RECORD ker = ir.Event.KeyEvent; KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
@@ -224,33 +233,111 @@ void PIKbdListener::readKeyboard() {
ke.modifiers = getModifiers(ker.dwControlKeyState, &shift); ke.modifiers = getModifiers(ker.dwControlKeyState, &shift);
// piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar); // piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar);
switch (ker.wVirtualKeyCode) { switch (ker.wVirtualKeyCode) {
case 8: PRIVATE->ret = 1; ke.key = Backspace; break; case 8:
case 33: PRIVATE->ret = 1; ke.key = PageUp; break; PRIVATE->ret = 1;
case 34: PRIVATE->ret = 1; ke.key = PageDown; break; ke.key = Backspace;
case 35: PRIVATE->ret = 1; ke.key = End; break; break;
case 36: PRIVATE->ret = 1; ke.key = Home; break; case 33:
case 37: PRIVATE->ret = 1; ke.key = LeftArrow; break; PRIVATE->ret = 1;
case 38: PRIVATE->ret = 1; ke.key = UpArrow; break; ke.key = PageUp;
case 39: PRIVATE->ret = 1; ke.key = RightArrow; break; break;
case 40: PRIVATE->ret = 1; ke.key = DownArrow; break; case 34:
case 45: PRIVATE->ret = 1; ke.key = Insert; break; PRIVATE->ret = 1;
case 46: PRIVATE->ret = 1; ke.key = Delete; break; ke.key = PageDown;
break;
case 35:
PRIVATE->ret = 1;
ke.key = End;
break;
case 36:
PRIVATE->ret = 1;
ke.key = Home;
break;
case 37:
PRIVATE->ret = 1;
ke.key = LeftArrow;
break;
case 38:
PRIVATE->ret = 1;
ke.key = UpArrow;
break;
case 39:
PRIVATE->ret = 1;
ke.key = RightArrow;
break;
case 40:
PRIVATE->ret = 1;
ke.key = DownArrow;
break;
case 45:
PRIVATE->ret = 1;
ke.key = Insert;
break;
case 46:
PRIVATE->ret = 1;
ke.key = Delete;
break;
case '\r': case '\r':
case '\n': PRIVATE->ret = 1; ke.key = Return; break; case '\n':
case ' ': PRIVATE->ret = 1; ke.key = Space; break; PRIVATE->ret = 1;
case '\t': PRIVATE->ret = 1; ke.key = Tab; break; ke.key = Return;
case 112: PRIVATE->ret = 1; ke.key = F1; break; break;
case 113: PRIVATE->ret = 1; ke.key = F2; break; case ' ':
case 114: PRIVATE->ret = 1; ke.key = F3; break; PRIVATE->ret = 1;
case 115: PRIVATE->ret = 1; ke.key = F4; break; ke.key = Space;
case 116: PRIVATE->ret = 1; ke.key = F5; break; break;
case 117: PRIVATE->ret = 1; ke.key = F6; break; case '\t':
case 118: PRIVATE->ret = 1; ke.key = F7; break; PRIVATE->ret = 1;
case 119: PRIVATE->ret = 1; ke.key = F8; break; ke.key = Tab;
case 120: PRIVATE->ret = 1; ke.key = F9; break; break;
case 121: PRIVATE->ret = 1; ke.key = F10; break; case 112:
case 122: PRIVATE->ret = 1; ke.key = F11; break; PRIVATE->ret = 1;
case 123: PRIVATE->ret = 1; ke.key = F12; break; ke.key = F1;
break;
case 113:
PRIVATE->ret = 1;
ke.key = F2;
break;
case 114:
PRIVATE->ret = 1;
ke.key = F3;
break;
case 115:
PRIVATE->ret = 1;
ke.key = F4;
break;
case 116:
PRIVATE->ret = 1;
ke.key = F5;
break;
case 117:
PRIVATE->ret = 1;
ke.key = F6;
break;
case 118:
PRIVATE->ret = 1;
ke.key = F7;
break;
case 119:
PRIVATE->ret = 1;
ke.key = F8;
break;
case 120:
PRIVATE->ret = 1;
ke.key = F9;
break;
case 121:
PRIVATE->ret = 1;
ke.key = F10;
break;
case 122:
PRIVATE->ret = 1;
ke.key = F11;
break;
case 123:
PRIVATE->ret = 1;
ke.key = F12;
break;
default: default:
PRIVATE->ret = 1; PRIVATE->ret = 1;
rc[0] = 1; rc[0] = 1;
@@ -261,10 +348,15 @@ void PIKbdListener::readKeyboard() {
} }
break; break;
} }
if (ke.key == 0) {piMSleep(10); return;} if (ke.key == 0) {
} else {piMSleep(10); return;} piMSleep(10);
return;
} }
break; } else {
piMSleep(10);
return;
}
} break;
case MOUSE_EVENT: { case MOUSE_EVENT: {
MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent; MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent;
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -273,8 +365,7 @@ void PIKbdListener::readKeyboard() {
if (mer.dwEventFlags & MOUSE_WHEELED) { if (mer.dwEventFlags & MOUSE_WHEELED) {
memcpy((void *)(&we), (const void *)(&me), sizeof(me)); memcpy((void *)(&we), (const void *)(&me), sizeof(me));
we.action = MouseWheel; we.action = MouseWheel;
we.direction = short((mer.dwButtonState >> 8) & 0xFFFF) > 0; we.direction = short((mer.dwButtonState >> 16) & 0xFFFF) > 0;
//piCout << "wheel" << we.direction;
wheelEvent(we, kbddata_); wheelEvent(we, kbddata_);
break; break;
} else { } else {
@@ -297,27 +388,27 @@ void PIKbdListener::readKeyboard() {
prev_p_me = me; prev_p_me = me;
} }
tm_dbl.reset(); tm_dbl.reset();
} else if (mb < me.buttons)
me.action = MouseButtonRelease;
else {
if (mb != 0) piCoutObj << "WTF";
break;
} }
else if (mb < me.buttons) me.action = MouseButtonRelease;
else {if (mb != 0) piCoutObj << "WTF"; break;}
} }
me.buttons = mb; me.buttons = mb;
if (piCompareBinary(&prev_me, &me, sizeof(me))) if (piCompareBinary(&prev_me, &me, sizeof(me))) break;
break;
memcpy((void *)(&prev_me), (const void *)(&me), sizeof(me)); memcpy((void *)(&prev_me), (const void *)(&me), sizeof(me));
// PIString _s[] = {"press", "release", "dbl click", "move"}; // PIString _s[] = {"press", "release", "dbl click", "move"};
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y; // piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_); mouseEvent(me, kbddata_);
break; break;
} }
} } break;
break; default: piMSleep(10); return;
default:
piMSleep(10);
return;
} }
#else #else
tcsetattr(0, TCSANOW, &PRIVATE->tterm); tcsetattr(0, TCSANOW, &PRIVATE->tterm);
if (!PRIVATE->event.wait(0)) return;
PRIVATE->ret = read(0, rc, 8); PRIVATE->ret = read(0, rc, 8);
/*piCout << "key" << PIString(rc).replaceAll("\e", "\\e"); /*piCout << "key" << PIString(rc).replaceAll("\e", "\\e");
for (int i = 0; i < PRIVATE->ret; ++i) for (int i = 0; i < PRIVATE->ret; ++i)
@@ -327,8 +418,14 @@ void PIKbdListener::readKeyboard() {
for (int i = 0; i < PRIVATE->ret; ++i) for (int i = 0; i < PRIVATE->ret; ++i)
std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]); std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
std::cout << std::endl;*/ std::cout << std::endl;*/
if (rc[0] == 0) {piMSleep(10); return;} if (rc[0] == 0) {
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {piMSleep(10); return;} piMSleep(10);
return;
}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {
piMSleep(10);
return;
}
if (PRIVATE->ret == 1) { if (PRIVATE->ret == 1) {
if (rc[0] == 8) if (rc[0] == 8)
ke.key = Backspace; ke.key = Backspace;
@@ -347,7 +444,8 @@ void PIKbdListener::readKeyboard() {
ke.key = PIChar::fromConsole(rc[1]).unicode16Code(); ke.key = PIChar::fromConsole(rc[1]).unicode16Code();
} else { // escape-seq } else { // escape-seq
if (rc[1] == '\e') { // search for Alt if (rc[1] == '\e') { // search for Alt
for (int i = 1; i < 7; ++i) rc[i] = rc[i + 1]; for (int i = 1; i < 7; ++i)
rc[i] = rc[i + 1];
mod = 2; mod = 2;
PRIVATE->ret--; PRIVATE->ret--;
} }
@@ -396,7 +494,8 @@ void PIKbdListener::readKeyboard() {
for (int i = 2; i < 7; ++i) // search for modifier for (int i = 2; i < 7; ++i) // search for modifier
if (rc[i] == ';') { if (rc[i] == ';') {
mod |= rc[i + 1] - '0' - 1; mod |= rc[i + 1] - '0' - 1;
for (int j = i; j < 6; ++j) rc[j] = rc[j + 2]; for (int j = i; j < 6; ++j)
rc[j] = rc[j + 2];
rc[6] = rc[7] = 0; rc[6] = rc[7] = 0;
PRIVATE->ret -= 2; PRIVATE->ret -= 2;
break; break;
@@ -406,7 +505,8 @@ void PIKbdListener::readKeyboard() {
if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4) if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4)
if (rc[2] >= '1' && rc[2] <= '8') { if (rc[2] >= '1' && rc[2] <= '8') {
mod |= rc[2] - '0' - 1; mod |= rc[2] - '0' - 1;
for (int j = 2; j < 6; ++j) rc[j] = rc[j + 1]; for (int j = 2; j < 6; ++j)
rc[j] = rc[j + 1];
rc[7] = 0; rc[7] = 0;
PRIVATE->ret--; PRIVATE->ret--;
} }
@@ -432,11 +532,9 @@ void PIKbdListener::readKeyboard() {
cout << "'" << (char)(rc[i]) << "' "; cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/ cout << endl;*/
} }
if (ke.key == 0 && PRIVATE->ret > 1) if (ke.key == 0 && PRIVATE->ret > 1) ke.key = PIChar::fromSystem(rc).unicode16Code();
ke.key = PIChar(rc).unicode16Code();
#endif #endif
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1) if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1) ke.key = Return;
ke.key = Return;
if (exit_enabled && ke.key == exit_key) { if (exit_enabled && ke.key == exit_key) {
PIKbdListener::exiting = true; PIKbdListener::exiting = true;
return; return;
@@ -448,6 +546,18 @@ void PIKbdListener::readKeyboard() {
} }
void PIKbdListener::stop() {
PIThread::stop();
PRIVATE->event.interrupt();
}
bool PIKbdListener::stopAndWait(PISystemTime timeout) {
stop();
return waitForFinish(timeout);
}
void PIKbdListener::end() { void PIKbdListener::end() {
// cout << "list end" << endl; // cout << "list end" << endl;
#ifdef WINDOWS #ifdef WINDOWS

View File

@@ -27,17 +27,22 @@
#define PIKBDLISTENER_H #define PIKBDLISTENER_H
#include "pithread.h" #include "pithread.h"
#include "pitime.h"
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); // TODO: rewrite with condvar #define WAIT_FOR_EXIT \
while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); \
if (PIKbdListener::instance()) { \
if (!PIKbdListener::instance()->stopAndWait(PISystemTime::fromSeconds(1))) PIKbdListener::instance()->terminate(); \
}
class PIP_EXPORT PIKbdListener: public PIThread class PIP_EXPORT PIKbdListener: public PIThread {
{
PIOBJECT_SUBCLASS(PIKbdListener, PIThread); PIOBJECT_SUBCLASS(PIKbdListener, PIThread);
friend class PIConsole; friend class PIConsole;
friend class PITerminal; friend class PITerminal;
public:
public:
//! Special keyboard keys //! Special keyboard keys
enum SpecialKey { enum SpecialKey {
Tab /** Tab key */ = 0x09, Tab /** Tab key */ = 0x09,
@@ -81,7 +86,10 @@ public:
//! This struct contains information about pressed keyboard key //! This struct contains information about pressed keyboard key
struct PIP_EXPORT KeyEvent { struct PIP_EXPORT KeyEvent {
KeyEvent(int k = 0, KeyModifiers m = 0) {key = k; modifiers = m;} KeyEvent(int k = 0, KeyModifiers m = 0) {
key = k;
modifiers = m;
}
//! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey) //! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey)
int key; int key;
@@ -110,7 +118,12 @@ public:
//! This struct contains information about mouse action //! This struct contains information about mouse action
struct PIP_EXPORT MouseEvent { struct PIP_EXPORT MouseEvent {
MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {x = y = 0; action = a; buttons = b; modifiers = m;} MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {
x = y = 0;
action = a;
buttons = b;
modifiers = m;
}
//! Event X coordinate in view-space, from 0 //! Event X coordinate in view-space, from 0
int x; int x;
@@ -154,7 +167,9 @@ public:
void setSlot(KBFunc slot) { ret_func = slot; } void setSlot(KBFunc slot) { ret_func = slot; }
//! Set external function to "slot" //! Set external function to "slot"
void setSlot(std::function<void(KeyEvent)> slot) {ret_func = [slot](KeyEvent e, void *){slot(e);};} void setSlot(std::function<void(KeyEvent)> slot) {
ret_func = [slot](KeyEvent e, void *) { slot(e); };
}
//! Returns if exit key if awaiting //! Returns if exit key if awaiting
bool exitCaptured() const { return exit_enabled; } bool exitCaptured() const { return exit_enabled; }
@@ -167,11 +182,18 @@ public:
void readKeyboard(); void readKeyboard();
void stop();
bool stopAndWait(PISystemTime timeout = {});
//! Returns if keyboard listening is active (not running!) //! Returns if keyboard listening is active (not running!)
bool isActive() { return is_active; } bool isActive() { return is_active; }
EVENT_HANDLER(void, enableExitCapture) { enableExitCapture('Q'); } EVENT_HANDLER(void, enableExitCapture) { enableExitCapture('Q'); }
EVENT_HANDLER1(void, enableExitCapture, int, key) {exit_enabled = true; exit_key = key;} EVENT_HANDLER1(void, enableExitCapture, int, key) {
exit_enabled = true;
exit_key = key;
}
EVENT_HANDLER(void, disableExitCapture) { exit_enabled = false; } EVENT_HANDLER(void, disableExitCapture) { exit_enabled = false; }
EVENT_HANDLER(void, setActive) { setActive(true); } EVENT_HANDLER(void, setActive) { setActive(true); }
EVENT_HANDLER1(void, setActive, bool, yes); EVENT_HANDLER1(void, setActive, bool, yes);
@@ -234,39 +256,49 @@ private:
PRIVATE_DECLARATION(PIP_EXPORT) PRIVATE_DECLARATION(PIP_EXPORT)
KBFunc ret_func; KBFunc ret_func;
int exit_key; int exit_key;
bool exit_enabled, is_active; bool exit_enabled = false, is_active = true;
void * kbddata_; void * kbddata_;
char rc[8];
double dbl_interval; double dbl_interval;
PITimeMeasurer tm_dbl; PITimeMeasurer tm_dbl;
KeyEvent ke; KeyEvent ke;
MouseEvent me, prev_me, prev_p_me; MouseEvent me, prev_me, prev_p_me;
WheelEvent we; WheelEvent we;
static PIKbdListener * _object; static PIKbdListener * _object;
}; };
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Store operator //! \~english Store operator
//! \~russian Оператор сохранения //! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {s << v.x << v.y << v.action << v.buttons << v.modifiers; return s;} BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {
s << v.x << v.y << v.action << v.buttons << v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Restore operator //! \~english Restore operator
//! \~russian Оператор извлечения //! \~russian Оператор извлечения
BINARY_STREAM_READ (PIKbdListener::MouseEvent) {s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers; return s;} BINARY_STREAM_READ(PIKbdListener::MouseEvent) {
s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Store operator //! \~english Store operator
//! \~russian Оператор сохранения //! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {s << (*(PIKbdListener::MouseEvent*)&v) << v.direction; return s;} BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {
s << (*(PIKbdListener::MouseEvent *)&v) << v.direction;
return s;
}
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Restore operator //! \~english Restore operator
//! \~russian Оператор извлечения //! \~russian Оператор извлечения
BINARY_STREAM_READ (PIKbdListener::WheelEvent) {s >> (*(PIKbdListener::MouseEvent*)&v) >> v.direction; return s;} BINARY_STREAM_READ(PIKbdListener::WheelEvent) {
s >> (*(PIKbdListener::MouseEvent *)&v) >> v.direction;
return s;
}
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent) REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)

View File

@@ -27,16 +27,17 @@
#define PISCREEN_H #define PISCREEN_H
#include "pip_console_export.h" #include "pip_console_export.h"
#include "piscreentile.h"
#include "piscreendrawer.h" #include "piscreendrawer.h"
#include "piscreentile.h"
class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase class PIP_CONSOLE_EXPORT PIScreen
{ : public PIThread
, public PIScreenTypes::PIScreenBase {
PIOBJECT_SUBCLASS(PIScreen, PIThread); PIOBJECT_SUBCLASS(PIScreen, PIThread);
class SystemConsole; class SystemConsole;
public:
public:
//! Constructs %PIScreen with key handler "slot" and if "startNow" start it //! Constructs %PIScreen with key handler "slot" and if "startNow" start it
PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0); PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
@@ -72,7 +73,7 @@ public:
EVENT_HANDLER0(void, waitForFinish); EVENT_HANDLER0(void, waitForFinish);
EVENT_HANDLER0(void, start) { start(false); } EVENT_HANDLER0(void, start) { start(false); }
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();} EVENT_HANDLER1(void, start, bool, wait);
EVENT_HANDLER0(void, stop) { stop(false); } EVENT_HANDLER0(void, stop) { stop(false); }
EVENT_HANDLER1(void, stop, bool, clear); EVENT_HANDLER1(void, stop, bool, clear);
@@ -156,7 +157,6 @@ private:
PIKbdListener::KBFunc ret_func; PIKbdListener::KBFunc ret_func;
PIScreenTile root; PIScreenTile root;
PIScreenTile *tile_focus, *tile_dialog; PIScreenTile *tile_focus, *tile_dialog;
}; };

View File

@@ -35,9 +35,14 @@
class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile { class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile {
public: public:
TileVars(const PIString & n = PIString()); TileVars(const PIString & n = PIString());
protected: protected:
struct PIP_CONSOLE_EXPORT Variable { struct PIP_CONSOLE_EXPORT Variable {
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = PIScreenTypes::CellFormat(); ptr = 0;} Variable() {
nx = ny = type = offset = bitFrom = bitCount = size = 0;
format = PIScreenTypes::CellFormat();
ptr = 0;
}
bool isEmpty() const { return (ptr == 0); } bool isEmpty() const { return (ptr == 0); }
PIString name; PIString name;
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
@@ -69,9 +74,7 @@ protected:
}; };
class PIP_CONSOLE_EXPORT PIScreenConsoleTile: public PIScreenTile {
class PIP_CONSOLE_EXPORT PIScreenConsoleTile : public PIScreenTile
{
public: public:
PIScreenConsoleTile(); PIScreenConsoleTile();
}; };

View File

@@ -30,10 +30,10 @@
#include "piscreentypes.h" #include "piscreentypes.h"
#include "pistring.h" #include "pistring.h"
class PIP_CONSOLE_EXPORT PIScreenDrawer class PIP_CONSOLE_EXPORT PIScreenDrawer {
{
friend class PIScreen; friend class PIScreen;
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell>> & c); PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell>> & c);
public: public:
enum ArtChar { enum ArtChar {
LineVertical = 1, LineVertical = 1,
@@ -49,12 +49,49 @@ public:
void clear(); void clear();
void clearRect(int x0, int y0, int x1, int y1) { fillRect(x0, y0, x1, y1, ' '); } void clearRect(int x0, int y0, int x1, int y1) { fillRect(x0, y0, x1, y1, ' '); }
void drawPixel(int x, int y, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); void drawPixel(int x,
void drawLine(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); int y,
void drawRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); const PIChar & c,
void drawFrame(int x0, int y0, int x1, int y1, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::Color col_char = PIScreenTypes::Default,
void drawText(int x, int y, const PIString & s, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Transparent, PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::Color col_back = PIScreenTypes::Default,
void fillRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); PIScreenTypes::CharFlags flags_char = 0);
void drawLine(int x0,
int y0,
int x1,
int y1,
const PIChar & c,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void drawRect(int x0,
int y0,
int x1,
int y1,
const PIChar & c,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void drawFrame(int x0,
int y0,
int x1,
int y1,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void drawText(int x,
int y,
const PIString & s,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Transparent,
PIScreenTypes::CharFlags flags_char = 0);
void fillRect(int x0,
int y0,
int x1,
int y1,
const PIChar & c,
PIScreenTypes::Color col_char = PIScreenTypes::Default,
PIScreenTypes::Color col_back = PIScreenTypes::Default,
PIScreenTypes::CharFlags flags_char = 0);
void fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<PIScreenTypes::Cell>> & content); void fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<PIScreenTypes::Cell>> & content);
PIChar artChar(const ArtChar type) const { return arts_.value(type, PIChar(' ')); } PIChar artChar(const ArtChar type) const { return arts_.value(type, PIChar(' ')); }
@@ -65,7 +102,6 @@ private:
PIVector<PIVector<PIScreenTypes::Cell>> & cells; PIVector<PIVector<PIScreenTypes::Cell>> & cells;
int width, height; int width, height;
PIMap<ArtChar, PIChar> arts_; PIMap<ArtChar, PIChar> arts_;
}; };

View File

@@ -26,17 +26,20 @@
#ifndef PISCREENTILE_H #ifndef PISCREENTILE_H
#define PISCREENTILE_H #define PISCREENTILE_H
#include "pikbdlistener.h"
#include "pip_console_export.h" #include "pip_console_export.h"
#include "piscreentypes.h" #include "piscreentypes.h"
#include "pikbdlistener.h"
class PIScreenDrawer; class PIScreenDrawer;
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject { class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
friend class PIScreen; friend class PIScreen;
PIOBJECT_SUBCLASS(PIScreenTile, PIObject); PIOBJECT_SUBCLASS(PIScreenTile, PIObject);
public: public:
PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred); PIScreenTile(const PIString & n = PIString(),
PIScreenTypes::Direction d = PIScreenTypes::Vertical,
PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
virtual ~PIScreenTile(); virtual ~PIScreenTile();
void addTile(PIScreenTile * t); void addTile(PIScreenTile * t);
@@ -50,7 +53,12 @@ public:
void setFocus(); void setFocus();
bool hasFocus() const { return has_focus; } bool hasFocus() const { return has_focus; }
void setMargins(int m) { marginLeft = marginRight = marginTop = marginBottom = m; } void setMargins(int m) { marginLeft = marginRight = marginTop = marginBottom = m; }
void setMargins(int l, int r, int t, int b) {marginLeft = l; marginRight = r; marginTop = t; marginBottom = b;} void setMargins(int l, int r, int t, int b) {
marginLeft = l;
marginRight = r;
marginTop = t;
marginBottom = b;
}
int x() const { return x_; } int x() const { return x_; }
int y() const { return y_; } int y() const { return y_; }
@@ -69,7 +77,6 @@ public:
bool visible; bool visible;
protected: protected:
//! Returns desired tile size in "w" and "h" //! Returns desired tile size in "w" and "h"
virtual void sizeHint(int & w, int & h) const; virtual void sizeHint(int & w, int & h) const;
@@ -103,7 +110,6 @@ protected:
private: private:
int pw, ph; int pw, ph;
}; };

View File

@@ -32,6 +32,7 @@
class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile { class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile {
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile); PIOBJECT_SUBCLASS(TileSimple, PIScreenTile);
public: public:
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row; typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
TileSimple(const PIString & n = PIString()); TileSimple(const PIString & n = PIString());
@@ -39,6 +40,7 @@ public:
virtual ~TileSimple() {} virtual ~TileSimple() {}
PIVector<Row> content; PIVector<Row> content;
PIScreenTypes::Alignment alignment; PIScreenTypes::Alignment alignment;
protected: protected:
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
@@ -50,6 +52,7 @@ class TileList;
class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile { class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile {
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile); PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile);
friend class TileList; friend class TileList;
public: public:
TileScrollBar(const PIString & n = PIString()); TileScrollBar(const PIString & n = PIString());
virtual ~TileScrollBar() {} virtual ~TileScrollBar() {}
@@ -60,6 +63,7 @@ public:
int maximum() const { return maximum_; } int maximum() const { return maximum_; }
int value() const { return value_; } int value() const { return value_; }
int thickness; int thickness;
protected: protected:
void _check(); void _check();
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
@@ -72,6 +76,7 @@ protected:
class PIP_CONSOLE_EXPORT TileList: public PIScreenTile { class PIP_CONSOLE_EXPORT TileList: public PIScreenTile {
PIOBJECT_SUBCLASS(TileList, PIScreenTile); PIOBJECT_SUBCLASS(TileList, PIScreenTile);
public: public:
enum SelectionMode { enum SelectionMode {
NoSelection, NoSelection,
@@ -92,6 +97,7 @@ public:
SelectionMode selection_mode; SelectionMode selection_mode;
PISet<int> selected; PISet<int> selected;
int lhei, cur, offset; int lhei, cur, offset;
protected: protected:
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
void resizeEvent(int w, int h) override; void resizeEvent(int w, int h) override;
@@ -106,6 +112,7 @@ protected:
class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile { class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButton, PIScreenTile); PIOBJECT_SUBCLASS(TileButton, PIScreenTile);
public: public:
TileButton(const PIString & n = PIString()); TileButton(const PIString & n = PIString());
virtual ~TileButton() {} virtual ~TileButton() {}
@@ -114,6 +121,7 @@ public:
}; };
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
PIString text; PIString text;
protected: protected:
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
@@ -122,10 +130,9 @@ protected:
}; };
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile { class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile); PIOBJECT_SUBCLASS(TileButtons, PIScreenTile);
public: public:
TileButtons(const PIString & n = PIString()); TileButtons(const PIString & n = PIString());
virtual ~TileButtons() {} virtual ~TileButtons() {}
@@ -136,6 +143,7 @@ public:
PIScreenTypes::Alignment alignment; PIScreenTypes::Alignment alignment;
PIVector<Button> content; PIVector<Button> content;
int cur; int cur;
protected: protected:
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
@@ -151,6 +159,7 @@ protected:
class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile { class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile {
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile); PIOBJECT_SUBCLASS(TileCheck, PIScreenTile);
public: public:
TileCheck(const PIString & n = PIString()); TileCheck(const PIString & n = PIString());
virtual ~TileCheck() {} virtual ~TileCheck() {}
@@ -160,6 +169,7 @@ public:
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
PIString text; PIString text;
bool toggled; bool toggled;
protected: protected:
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
@@ -170,6 +180,7 @@ protected:
class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile { class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile {
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile); PIOBJECT_SUBCLASS(TileProgress, PIScreenTile);
public: public:
TileProgress(const PIString & n = PIString()); TileProgress(const PIString & n = PIString());
virtual ~TileProgress() {} virtual ~TileProgress() {}
@@ -178,6 +189,7 @@ public:
PIString suffix; PIString suffix;
double maximum; double maximum;
double value; double value;
protected: protected:
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
@@ -186,11 +198,13 @@ protected:
class PIP_CONSOLE_EXPORT TilePICout: public TileList { class PIP_CONSOLE_EXPORT TilePICout: public TileList {
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile); PIOBJECT_SUBCLASS(TilePICout, PIScreenTile);
public: public:
TilePICout(const PIString & n = PIString()); TilePICout(const PIString & n = PIString());
virtual ~TilePICout() {} virtual ~TilePICout() {}
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
int max_lines; int max_lines;
protected: protected:
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override; bool keyEvent(PIKbdListener::KeyEvent key) override;
@@ -199,12 +213,14 @@ protected:
class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile { class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile {
PIOBJECT_SUBCLASS(TileInput, PIScreenTile); PIOBJECT_SUBCLASS(TileInput, PIScreenTile);
public: public:
TileInput(const PIString & n = PIString()); TileInput(const PIString & n = PIString());
virtual ~TileInput() {} virtual ~TileInput() {}
PIScreenTypes::CellFormat format; PIScreenTypes::CellFormat format;
PIString text; PIString text;
int max_length; int max_length;
protected: protected:
void sizeHint(int & w, int & h) const override; void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override; void drawEvent(PIScreenDrawer * d) override;

View File

@@ -110,7 +110,10 @@ namespace PIScreenTypes {
}; };
struct PIP_CONSOLE_EXPORT Cell { struct PIP_CONSOLE_EXPORT Cell {
Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {symbol = c; format = f;} Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {
symbol = c;
format = f;
}
CellFormat format; CellFormat format;
PIChar symbol; PIChar symbol;
bool operator==(const Cell & c) const { return format == c.format && symbol == c.symbol; } bool operator==(const Cell & c) const { return format == c.format && symbol == c.symbol; }
@@ -120,7 +123,8 @@ namespace PIScreenTypes {
if (c.format.color_back == Transparent) { if (c.format.color_back == Transparent) {
format.color_char = c.format.color_char; format.color_char = c.format.color_char;
format.flags = c.format.flags; format.flags = c.format.flags;
} else format = c.format; } else
format = c.format;
return *this; return *this;
} }
}; };
@@ -140,7 +144,7 @@ namespace PIScreenTypes {
virtual void tileSetFocusInternal(PIScreenTile *) {} virtual void tileSetFocusInternal(PIScreenTile *) {}
}; };
} } // namespace PIScreenTypes
// inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;} // inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
@@ -149,23 +153,35 @@ namespace PIScreenTypes {
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Store operator //! \~english Store operator
//! \~russian Оператор сохранения //! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIScreenTypes::Cell) {s << v.format.raw_format << v.symbol; return s;} BINARY_STREAM_WRITE(PIScreenTypes::Cell) {
s << v.format.raw_format << v.symbol;
return s;
}
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Restore operator //! \~english Restore operator
//! \~russian Оператор извлечения //! \~russian Оператор извлечения
BINARY_STREAM_READ (PIScreenTypes::Cell) {s >> v.format.raw_format >> v.symbol; return s;} BINARY_STREAM_READ(PIScreenTypes::Cell) {
s >> v.format.raw_format >> v.symbol;
return s;
}
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Store operator //! \~english Store operator
//! \~russian Оператор сохранения //! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIScreenTypes::TileEvent) {s << v.type << v.data; return s;} BINARY_STREAM_WRITE(PIScreenTypes::TileEvent) {
s << v.type << v.data;
return s;
}
//! \relatesalso PIBinaryStream //! \relatesalso PIBinaryStream
//! \~english Restore operator //! \~english Restore operator
//! \~russian Оператор извлечения //! \~russian Оператор извлечения
BINARY_STREAM_READ (PIScreenTypes::TileEvent) {s >> v.type >> v.data; return s;} BINARY_STREAM_READ(PIScreenTypes::TileEvent) {
s >> v.type >> v.data;
return s;
}
REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent) REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent)

View File

@@ -26,16 +26,15 @@
#ifndef PITERMINAL_H #ifndef PITERMINAL_H
#define PITERMINAL_H #define PITERMINAL_H
#include "pip_console_export.h"
#include "pikbdlistener.h" #include "pikbdlistener.h"
#include "pip_console_export.h"
#include "piscreentypes.h" #include "piscreentypes.h"
class PIP_CONSOLE_EXPORT PITerminal: public PIThread class PIP_CONSOLE_EXPORT PITerminal: public PIThread {
{
PIOBJECT_SUBCLASS(PITerminal, PIThread); PIOBJECT_SUBCLASS(PITerminal, PIThread);
public:
public:
//! Constructs %PITerminal //! Constructs %PITerminal
PITerminal(); PITerminal();
@@ -53,6 +52,7 @@ public:
bool initialize(); bool initialize();
void destroy(); void destroy();
private: private:
void initPrivate(); void initPrivate();
void readConsole(); void readConsole();
@@ -73,7 +73,6 @@ private:
bool cursor_blink, cursor_visible; bool cursor_blink, cursor_visible;
PITimeMeasurer cursor_tm; PITimeMeasurer cursor_tm;
PIVector<PIVector<PIScreenTypes::Cell>> cells; PIVector<PIVector<PIScreenTypes::Cell>> cells;
}; };

View File

@@ -19,12 +19,29 @@
#include "picontainers.h" #include "picontainers.h"
#include "piliterals_bytes.h"
const size_t minAlloc = 64;
#if defined(PIP_CONTAINERS_MIN_ALLOC)
# define ACTUAL_MIN_ALLOC PIP_CONTAINERS_MIN_ALLOC
#else
# define ACTUAL_MIN_ALLOC 64
#endif
#if defined(PIP_CONTAINERS_MAX_POT_ALLOC)
# define ACTUAL_MAX_POT_ALLOC PIP_CONTAINERS_MAX_POT_ALLOC
#else
# define ACTUAL_MAX_POT_ALLOC 64_MiB
#endif
const size_t minAlloc = ACTUAL_MIN_ALLOC;
const size_t maxPoTAlloc = ACTUAL_MAX_POT_ALLOC;
size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) { size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) {
size_t ret = 0, elc = 1; size_t ret = 0;
size_t elc = 1;
while (elc * szof < minAlloc) { while (elc * szof < minAlloc) {
elc *= 2; elc *= 2;
++ret; ++ret;
@@ -32,3 +49,15 @@ size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) {
// printf("calcMinCount sizeof = %d, min_count = %d, pot = %d\n", szof, elc, ret); // printf("calcMinCount sizeof = %d, min_count = %d, pot = %d\n", szof, elc, ret);
return ret; return ret;
} }
size_t _PIContainerConstantsBase::calcMaxCountForPoT(size_t szof) {
// printf("calcMaxCountForPoT sizeof = %d, size = %d\n", szof, maxPoTAlloc / szof);
return maxPoTAlloc / szof;
}
size_t _PIContainerConstantsBase::calcStepAfterPoT(size_t szof) {
// printf("calcStepAfterPoT sizeof = %d, size = %d\n", szof, calcMaxCountForPoT(szof));
return calcMaxCountForPoT(szof);
}

View File

@@ -41,12 +41,12 @@
#else #else
# include <malloc.h> # include <malloc.h>
#endif #endif
#include <initializer_list>
#include <type_traits>
#include <string.h>
#include <new>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <initializer_list>
#include <new>
#include <string.h>
#include <type_traits>
template<typename C> template<typename C>
@@ -58,6 +58,7 @@ public:
typename C::reverse_iterator end() { return c_.rend(); } typename C::reverse_iterator end() { return c_.rend(); }
typename C::const_reverse_iterator begin() const { return c_.rbegin(); } typename C::const_reverse_iterator begin() const { return c_.rbegin(); }
typename C::const_reverse_iterator end() const { return c_.rend(); } typename C::const_reverse_iterator end() const { return c_.rend(); }
private: private:
C & c_; C & c_;
}; };
@@ -66,20 +67,62 @@ private:
class PIP_EXPORT _PIContainerConstantsBase { class PIP_EXPORT _PIContainerConstantsBase {
public: public:
static size_t calcMinCountPoT(size_t szof); static size_t calcMinCountPoT(size_t szof);
static size_t calcMaxCountForPoT(size_t szof);
static size_t calcStepAfterPoT(size_t szof);
}; };
template<typename T> template<typename T>
class _PIContainerConstants { class _PIContainerConstants {
public: public:
static size_t minCountPoT() {static size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T)); return ret;} // minimum elements for container
static size_t minCountPoT() {
static const size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T));
return ret;
}
// maximum elements for 2^n growth
static size_t maxCountForPoT() {
static const size_t ret = _PIContainerConstantsBase::calcMaxCountForPoT(sizeof(T));
return ret;
}
// add elements after 2^n growth
static size_t stepAfterPoT() {
static const size_t ret = _PIContainerConstantsBase::calcStepAfterPoT(sizeof(T));
return ret;
}
static size_t calcNewSize(size_t old_size, size_t new_size) {
if (new_size == 0) return 0;
if (new_size < maxCountForPoT()) {
if (old_size * 2 >= new_size && old_size < new_size) {
return old_size * 2;
}
ssize_t t = minCountPoT();
new_size -= 1;
while (new_size >> t)
++t;
return (1 << t);
} else {
size_t ret = old_size;
while (ret < new_size)
ret += stepAfterPoT();
return ret;
}
return 0;
}
}; };
//! \brief //! \brief
//! \~english Template reverse wrapper over any container //! \~english Template reverse wrapper over any container
//! \~russian Шаблонная функция обертки любого контейнера для обратного доступа через итераторы //! \~russian Шаблонная функция обертки любого контейнера для обратного доступа через итераторы
template <typename C> _PIReverseWrapper<C> PIReverseWrap(C & c) {return _PIReverseWrapper<C>(c);} template<typename C>
template <typename C> _PIReverseWrapper<C> PIReverseWrap(const C & c) {return _PIReverseWrapper<C>(c);} _PIReverseWrapper<C> PIReverseWrap(C & c) {
return _PIReverseWrapper<C>(c);
}
template<typename C>
_PIReverseWrapper<C> PIReverseWrap(const C & c) {
return _PIReverseWrapper<C>(c);
}
//! \brief //! \brief
@@ -177,7 +220,9 @@ template <typename C> _PIReverseWrapper<C> PIReverseWrap(const C & c) {return _P
//! \~russian Порядок обхода для функции изменения размерности reshape(). //! \~russian Порядок обхода для функции изменения размерности reshape().
//! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape() //! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape()
enum ReshapeOrder { enum ReshapeOrder {
ReshapeByRow /*! \~english Traversing elements by line, just as they stay in memory \~russian Обход элементов построчно, так же как они находятся в памяти */, ReshapeByRow /*! \~english Traversing elements by line, just as they stay in memory \~russian Обход элементов построчно, так же как они
находятся в памяти */
,
ReshapeByColumn /*! \~english Traversing elements by column \~russian Обход элементов по столбцам */, ReshapeByColumn /*! \~english Traversing elements by column \~russian Обход элементов по столбцам */,
}; };

View File

@@ -180,12 +180,12 @@
#ifndef PICONTAINERSMODULE_H #ifndef PICONTAINERSMODULE_H
#define PICONTAINERSMODULE_H #define PICONTAINERSMODULE_H
#include "pivector.h"
#include "pideque.h" #include "pideque.h"
#include "pimap.h" #include "pimap.h"
#include "piqueue.h" #include "piqueue.h"
#include "piset.h" #include "piset.h"
#include "pistack.h" #include "pistack.h"
#include "pivector.h"
#include "pivector2d.h" #include "pivector2d.h"

View File

@@ -75,9 +75,9 @@
//! if the number of elements is known beforehand. //! if the number of elements is known beforehand.
//! //!
//! The complexity (efficiency) of common operations on PIDeque is as follows: //! The complexity (efficiency) of common operations on PIDeque is as follows:
//! - Random access - constant 𝓞(1) //! - Random access - constant O(1)
//! - Insertion or removal of elements at the end or begin - amortized constant 𝓞(1) //! - Insertion or removal of elements at the end or begin - amortized constant O(1)
//! - Insertion or removal of elements - linear in the distance to the end of the array 𝓞(n) //! - Insertion or removal of elements - linear in the distance to the end of the array O(n)
//! //!
//! \~russian //! \~russian
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы, //! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
@@ -109,9 +109,9 @@
//! если количество элементов известно заранее. //! если количество элементов известно заранее.
//! //!
//! Сложность (эффективность) обычных операций над PIDeque следующая: //! Сложность (эффективность) обычных операций над PIDeque следующая:
//! - Произвольный доступ — постоянная 𝓞(1) //! - Произвольный доступ — постоянная O(1)
//! - Вставка и удаление элементов в конце или начале — амортизированная постоянная 𝓞(1) //! - Вставка и удаление элементов в конце или начале — амортизированная постоянная O(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n) //! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n)
//! //!
//! \~\sa \a PIVector, \a PIMap //! \~\sa \a PIVector, \a PIMap
template<typename T> template<typename T>
@@ -127,13 +127,11 @@ public:
//! \~english Constructs an empty array. //! \~english Constructs an empty array.
//! \~russian Создает пустой массив. //! \~russian Создает пустой массив.
inline PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque() { PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) }
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
//! \~english Copy constructor. //! \~english Copy constructor.
//! \~russian Копирующий конструктор. //! \~russian Копирующий конструктор.
inline PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(const PIDeque<T> & other) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(other.pid_size); alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size); newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
@@ -148,7 +146,7 @@ public:
//! PIDeque <int> v{1,2,3}; //! PIDeque <int> v{1,2,3};
//! piCout << v; // {1, 2, 3} //! piCout << v; // {1, 2, 3}
//! \endcode //! \endcode
inline PIDeque(std::initializer_list<T> init_list): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(std::initializer_list<T> init_list) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(init_list.size()); alloc_forward(init_list.size());
newT(pid_data, init_list.begin(), init_list.size()); newT(pid_data, init_list.begin(), init_list.size());
@@ -158,7 +156,7 @@ public:
//! This constructor reserve `size` and copy from `data` pointer. //! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`. //! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`. //! То есть выделяет память для `size` элементов и копирует данные из указателя `data`.
inline PIDeque(const T * data, size_t size): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(const T * data, size_t size) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(size); alloc_forward(size);
newT(pid_data + pid_start, data, pid_size); newT(pid_data + pid_start, data, pid_size);
@@ -166,9 +164,9 @@ public:
//! \~english Contructs array with size `size` filled elements `e`. //! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `e`. //! \~russian Создает массив из `size` элементов заполненных `e`.
inline PIDeque(size_t pid_size, const T & e = T()): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline explicit PIDeque(size_t pid_size, const T & e = T()) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, e); expand(pid_size, e);
} }
//! \~english Contructs array with size `size` and elements created by function `f(size_t i)`. //! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
@@ -184,31 +182,34 @@ public:
//! PIDeque <int> v(5, [](size_t i){return i*2;}); //! PIDeque <int> v(5, [](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4, 6, 8} //! piCout << v; // {0, 2, 4, 6, 8}
//! \endcode //! \endcode
inline PIDeque(size_t piv_size, std::function<T(size_t i)> f): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) { inline PIDeque(size_t piv_size, std::function<T(size_t i)> f) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f); expand(piv_size, f);
} }
//! \~english Move constructor. //! \~english Move constructor.
//! \~russian Перемещающий конструктор. //! \~russian Перемещающий конструктор.
inline PIDeque(PIDeque<T> && other): pid_data(other.pid_data), pid_size(other.pid_size), pid_rsize(other.pid_rsize), pid_start(other.pid_start) { inline PIDeque(PIDeque<T> && other) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
pid_data = other.pid_data;
pid_size = other.pid_size;
pid_rsize = other.pid_rsize;
pid_start = other.pid_start;
other._reset(); other._reset();
} }
inline virtual ~PIDeque() { inline ~PIDeque() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize)) PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
deleteT(pid_data + pid_start, pid_size); deleteT(pid_data + pid_start, pid_size);
dealloc(); dealloc();
_reset();
} }
//! \~english Assign operator. //! \~english Assign operator.
//! \~russian Оператор присваивания. //! \~russian Оператор присваивания.
inline PIDeque<T> & operator=(const PIDeque<T> & other) { inline PIDeque<T> & operator=(const PIDeque<T> & other) {
if (this == &other) return *this; if (this == &other) return *this;
deleteT(pid_data + pid_start, pid_size); clear();
alloc_forward(other.pid_size); alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size); newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
return *this; return *this;
@@ -223,10 +224,12 @@ public:
class iterator { class iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent; PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -246,7 +249,7 @@ public:
return *this; return *this;
} }
inline iterator operator++(int) { inline iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -255,7 +258,7 @@ public:
return *this; return *this;
} }
inline iterator operator--(int) { inline iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -283,9 +286,7 @@ public:
tmp -= p; tmp -= p;
return tmp; return tmp;
} }
friend inline std::ptrdiff_t operator -(const iterator & it1, const iterator & it2) { friend inline std::ptrdiff_t operator-(const iterator & it1, const iterator & it2) { return it1.pos - it2.pos; }
return it1.pos - it2.pos;
}
friend inline iterator operator+(size_t p, const iterator & it) { return it + p; } friend inline iterator operator+(size_t p, const iterator & it) { return it + p; }
friend inline iterator operator+(const iterator & it, size_t p) { friend inline iterator operator+(const iterator & it, size_t p) {
@@ -296,26 +297,20 @@ public:
inline bool operator==(const iterator & it) const { return (pos == it.pos); } inline bool operator==(const iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const iterator & it) const { return (pos != it.pos); } inline bool operator!=(const iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const iterator & it1, const iterator & it2) { friend inline bool operator<(const iterator & it1, const iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const iterator & it1, const iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const iterator & it1, const iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const iterator & it1, const iterator & it2) { friend inline bool operator>=(const iterator & it1, const iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const iterator & it1, const iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const iterator & it1, const iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_iterator { class const_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline const_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline const_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent; const PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -333,7 +328,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator++(int) { inline const_iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -342,7 +337,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator--(int) { inline const_iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -370,9 +365,7 @@ public:
tmp -= p; tmp -= p;
return tmp; return tmp;
} }
friend inline std::ptrdiff_t operator -(const const_iterator & it1, const const_iterator & it2) { friend inline std::ptrdiff_t operator-(const const_iterator & it1, const const_iterator & it2) { return it1.pos - it2.pos; }
return it1.pos - it2.pos;
}
friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; } friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; }
friend inline const_iterator operator+(const const_iterator & it, size_t p) { friend inline const_iterator operator+(const const_iterator & it, size_t p) {
@@ -383,26 +376,20 @@ public:
inline bool operator==(const const_iterator & it) const { return (pos == it.pos); } inline bool operator==(const const_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); } inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const const_iterator & it1, const const_iterator & it2) { friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const const_iterator & it1, const const_iterator & it2) { friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const const_iterator & it1, const const_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class reverse_iterator { class reverse_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline reverse_iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline reverse_iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent; PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -422,7 +409,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator++(int) { inline reverse_iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -431,7 +418,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator--(int) { inline reverse_iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -459,9 +446,7 @@ public:
tmp -= p; tmp -= p;
return tmp; return tmp;
} }
friend inline std::ptrdiff_t operator -(const reverse_iterator & it1, const reverse_iterator & it2) { friend inline std::ptrdiff_t operator-(const reverse_iterator & it1, const reverse_iterator & it2) { return it2.pos - it1.pos; }
return it2.pos - it1.pos;
}
friend inline reverse_iterator operator+(size_t p, const reverse_iterator & it) { return it + p; } friend inline reverse_iterator operator+(size_t p, const reverse_iterator & it) { return it + p; }
friend inline reverse_iterator operator+(const reverse_iterator & it, size_t p) { friend inline reverse_iterator operator+(const reverse_iterator & it, size_t p) {
@@ -472,26 +457,20 @@ public:
inline bool operator==(const reverse_iterator & it) const { return (pos == it.pos); } inline bool operator==(const reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); } inline bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const reverse_iterator & it1, const reverse_iterator & it2) { friend inline bool operator<(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const reverse_iterator & it1, const reverse_iterator & it2) { friend inline bool operator>=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_reverse_iterator { class const_reverse_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: private:
inline const_reverse_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {} inline const_reverse_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent; const PIDeque<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -508,7 +487,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator++(int) { inline const_reverse_iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -517,7 +496,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator--(int) { inline const_reverse_iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -558,18 +537,10 @@ public:
inline bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); } inline bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); } inline bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { friend inline bool operator<(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { friend inline bool operator>=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
@@ -613,7 +584,8 @@ public:
//! \~english Returns a reverse iterator to the element. //! \~english Returns a reverse iterator to the element.
//! following the last element of the reversed array. //! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент, следующий за последним элементом. //! \~russian Обратный итератор на элемент,
//! следующий за последним элементом.
//! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png) //! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png)
//! //!
//! \~english It corresponds to the element preceding the first element of the non-reversed array. //! \~english It corresponds to the element preceding the first element of the non-reversed array.
@@ -750,6 +722,34 @@ public:
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти. //! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline const T & at(size_t index) const { return pid_data[pid_start + index]; } inline const T & at(size_t index) const { return pid_data[pid_start + index]; }
//! \~english Returns the first element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает первый элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a indexWhere()
inline const T & atWhere(std::function<bool(const T & e)> test, ssize_t start = 0, const T & def = T()) const {
const ssize_t i = indexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Returns the last element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает последний элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a lastIndexWhere()
inline const T & lastAtWhere(std::function<bool(const T & e)> test, ssize_t start = -1, const T & def = T()) const {
const ssize_t i = lastIndexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Last element. //! \~english Last element.
//! \~russian Последний элемент массива. //! \~russian Последний элемент массива.
//! \~\details //! \~\details
@@ -804,7 +804,7 @@ public:
//! возвращается **false**, что означает, что массив даже не просматривается. //! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<int> v{1, 2, 3, 4}; //! PIDeque<int> v{1, 2, 3, 4};
@@ -831,6 +831,33 @@ public:
return false; return false;
} }
//! \~english Tests if all elements of `v` exists in the array.
//! \~russian Проверяет наличие всех элементов `v` в массиве.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4};
//! piCout << v.contains({1,4}); // true
//! piCout << v.contains({1,5}); // false
//! \endcode
//! \~\sa \a every(), \a any(), \a entries(), \a forEach()
inline bool contains(const PIDeque<T> & v, ssize_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (const T & e: v) {
bool c = false;
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
if (e == pid_data[i]) {
c = true;
break;
}
}
if (!c) return false;
}
return true;
}
//! \~english Count elements equal `e` in the array. //! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве. //! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details //! \~\details
@@ -847,7 +874,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<int> v{2, 2, 4, 2, 6}; //! PIDeque<int> v{2, 2, 4, 2, 6};
@@ -887,7 +914,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexWhere() //! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexWhere()
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const { inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const {
@@ -920,7 +947,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<int> v{2, 5, 9}; //! PIDeque<int> v{2, 5, 9};
@@ -963,7 +990,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIDeque<PIString> v{"do", "re", "mi", "re"}; //! PIDeque<PIString> v{"do", "re", "mi", "re"};
@@ -1005,7 +1032,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1022,9 +1049,9 @@ public:
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const { inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start >= size_s()) start = pid_size - 1; if (start >= size_s()) start = pid_size - 1;
if (start < 0) start = pid_size + start; if (start < 0) start = pid_size + start;
for (size_t i = pid_start + size_t(start); i >= pid_start; --i) { for (ssize_t i = ssize_t(pid_start) + start; i >= ssize_t(pid_start); --i) {
if (e == pid_data[i]) { if (e == pid_data[i]) {
return ssize_t(i) - pid_start; return i - ssize_t(pid_start);
} }
} }
return -1; return -1;
@@ -1050,7 +1077,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1058,9 +1085,9 @@ public:
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const { inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
if (start >= size_s()) start = pid_size - 1; if (start >= size_s()) start = pid_size - 1;
if (start < 0) start = pid_size + start; if (start < 0) start = pid_size + start;
for (size_t i = pid_start + size_t(start); i >= pid_start; --i) { for (ssize_t i = ssize_t(pid_start) + start; i >= ssize_t(pid_start); --i) {
if (test(pid_data[i])) { if (test(pid_data[i])) {
return ssize_t(i) - pid_start; return i - ssize_t(pid_start);
} }
} }
return -1; return -1;
@@ -1119,7 +1146,7 @@ public:
PIDeque<T> getRange(size_t index, size_t count) const { PIDeque<T> getRange(size_t index, size_t count) const {
if (index >= pid_size || count == 0) return PIDeque<T>(); if (index >= pid_size || count == 0) return PIDeque<T>();
if (index + count > pid_size) count = pid_size - index; if (index + count > pid_size) count = pid_size - index;
return PIDeque(&(pid_data[pid_start + index]), count); return PIDeque(pid_data + pid_start + index, count);
} }
//! \~english Clear array, remove all elements. //! \~english Clear array, remove all elements.
@@ -1129,16 +1156,14 @@ public:
//! \~english Reserved memory will not be released. //! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится. //! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize() //! \~\sa \a resize()
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & clear() { inline PIDeque<T> & clear() {
resize(0); deleteT(pid_data + pid_start, pid_size);
pid_size = 0;
pid_start = (pid_rsize - pid_size) / 2;
return *this; return *this;
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & clear() { inline PIDeque<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size) PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size)
pid_size = 0; pid_size = 0;
@@ -1190,16 +1215,12 @@ public:
//! \~english First does `resize(new_size)` then `fill(e)`. //! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`. //! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize() //! \~\sa \a fill(), \a resize()
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & e) { inline PIDeque<T> & assign(size_t new_size, const T & e) {
resize(new_size); resize(new_size);
return fill(e); return fill(e);
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & e) { inline PIDeque<T> & assign(size_t new_size, const T & e) {
_resizeRaw(new_size); _resizeRaw(new_size);
return fill(e); return fill(e);
@@ -1217,20 +1238,12 @@ public:
//! лишние элементы удаляются с конца массива. //! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, const T & e = T()) { inline PIDeque<T> & resize(size_t new_size, const T & e = T()) {
if (new_size == 0) return clear();
if (new_size < pid_size) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(pid_data + pid_start + new_size, pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) { } else if (new_size > pid_size) {
pid_start = (pid_rsize - pid_size) / 2; expand(new_size, e);
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, e);
}
} }
return *this; return *this;
} }
@@ -1247,41 +1260,31 @@ public:
//! лишние элементы удаляются с конца массива. //! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) { inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size == 0) return clear();
if (new_size < pid_size) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(pid_data + pid_start + new_size, pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) { } else if (new_size > pid_size) {
pid_start = (pid_rsize - pid_size) / 2; expand(new_size, f);
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f(i));
}
} }
return *this; return *this;
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & _resizeRaw(size_t new_size) { inline PIDeque<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
if (new_size > pid_size) { if (new_size > pid_size) {
PIINTROSPECTION_CONTAINER_USED(T, (new_size - pid_size)); PIINTROSPECTION_CONTAINER_USED(T, (new_size - pid_size));
} }
if (new_size < pid_size) { if (new_size < pid_size) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size - new_size)); PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size - new_size));
} }
#endif
alloc_forward(new_size); alloc_forward(new_size);
return *this; return *this;
} }
inline void _copyRaw(T * dst, const T * src, size_t size) { inline void _copyRaw(T * dst, const T * src, size_t size) { newT(dst, src, size); }
newT(dst, src, size);
}
//! \~english Attempts to allocate memory for at least `new_size` elements. //! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов. //! \~russian Резервируется память под как минимум `new_size` элементов.
@@ -1299,7 +1302,7 @@ public:
//! \~\sa \a size(), \a capacity(), \a resize() //! \~\sa \a size(), \a capacity(), \a resize()
inline PIDeque<T> & reserve(size_t new_size) { inline PIDeque<T> & reserve(size_t new_size) {
if (new_size <= pid_rsize) return *this; if (new_size <= pid_rsize) return *this;
size_t os = pid_size; const size_t os = pid_size;
alloc_forward(new_size); alloc_forward(new_size);
pid_size = os; pid_size = os;
return *this; return *this;
@@ -1319,17 +1322,21 @@ public:
inline PIDeque<T> & insert(size_t index, const T & e = T()) { inline PIDeque<T> & insert(size_t index, const T & e = T()) {
if (index == pid_size) return push_back(e); if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); const bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
alloc_forward(pid_size + 1); alloc_forward(pid_size + 1);
if (index < pid_size - 1) { if (index < pid_size - 1) {
size_t os = pid_size - index - 1; const size_t os = pid_size - index - 1;
memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + 1, -1); alloc_backward(pid_size + 1, -1);
if (index > 0) { if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + 1),
index * sizeof(T));
} }
} }
elementNew(pid_data + pid_start + index, e); elementNew(pid_data + pid_start + index, e);
@@ -1345,17 +1352,21 @@ public:
inline PIDeque<T> & insert(size_t index, T && e) { inline PIDeque<T> & insert(size_t index, T && e) {
if (index == pid_size) return push_back(e); if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); const bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
alloc_forward(pid_size + 1); alloc_forward(pid_size + 1);
if (index < pid_size - 1) { if (index < pid_size - 1) {
size_t os = pid_size - index - 1; const size_t os = pid_size - index - 1;
memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + 1, -1); alloc_backward(pid_size + 1, -1);
if (index > 0) { if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + 1),
index * sizeof(T));
} }
} }
elementNew(pid_data + pid_start + index, std::move(e)); elementNew(pid_data + pid_start + index, std::move(e));
@@ -1372,21 +1383,25 @@ public:
if (v.isEmpty()) return *this; if (v.isEmpty()) return *this;
#ifndef NDEBUG #ifndef NDEBUG
if (&v == this) { if (&v == this) {
printf("error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(&v != this); assert(&v != this);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); const bool dir = v.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
ssize_t os = pid_size - index; const ssize_t os = pid_size - index;
alloc_forward(pid_size + v.pid_size); alloc_forward(pid_size + v.pid_size);
if (os > 0) { if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start + v.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start + index + v.pid_size),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + v.pid_size, -v.pid_size); alloc_backward(pid_size + v.pid_size, -v.pid_size);
if (index > 0) { if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + v.pid_size])), index * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + v.pid_size),
index * sizeof(T));
} }
} }
newT(pid_data + pid_start + index, v.pid_data + v.pid_start, v.pid_size); newT(pid_data + pid_start + index, v.pid_data + v.pid_start, v.pid_size);
@@ -1404,17 +1419,22 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove() //! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) { inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) {
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); if (init_list.size() == 0) return *this;
const bool dir = init_list.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
ssize_t os = ssize_t(pid_size) - index; const ssize_t os = ssize_t(pid_size) - index;
alloc_forward(pid_size + init_list.size()); alloc_forward(pid_size + init_list.size());
if (os > 0) { if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start + init_list.size()])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start + index + init_list.size()),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
} }
} else { } else {
alloc_backward(pid_size + init_list.size(), -init_list.size()); alloc_backward(pid_size + init_list.size(), -init_list.size());
if (index > 0) { if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + init_list.size()])), index * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + init_list.size()),
index * sizeof(T));
} }
} }
newT(pid_data + pid_start + index, init_list.begin(), init_list.size()); newT(pid_data + pid_start + index, init_list.begin(), init_list.size());
@@ -1433,22 +1453,27 @@ public:
inline PIDeque<T> & remove(size_t index, size_t count = 1) { inline PIDeque<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this; if (count == 0) return *this;
if (index + count >= pid_size) { if (index + count >= pid_size) {
resize(index); if (index < pid_size) {
return *this; deleteT(pid_data + pid_start + index, pid_size - index);
} pid_size = index;
size_t os = pid_size - index - count;
deleteT(&(pid_data[index + pid_start]), count);
if (os <= index) {
if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
} }
} else {
const size_t os = pid_size - index - count;
deleteT(pid_data + pid_start + index, count);
if (os <= index) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index),
reinterpret_cast<const void *>(pid_data + pid_start + index + count),
os * sizeof(T));
} else { } else {
if (index > 0) { if (index > 0) {
memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + pid_start + count),
reinterpret_cast<const void *>(pid_data + pid_start),
index * sizeof(T));
} }
pid_start += count; pid_start += count;
} }
pid_size -= count; pid_size -= count;
}
return *this; return *this;
} }
@@ -1469,11 +1494,11 @@ public:
//! \~\details //! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved. //! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using operator<. //! Elements are compared using operator<.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort). //! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`. //! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется. //! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется оператор `operator<`. //! Для сравнения элементов используется оператор `operator<`.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). //! Для сортировки используется функция [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort).
//! Сложность сортировки `O(N·log(N))`. //! Сложность сортировки `O(N·log(N))`.
//! \~\code //! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3}; //! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
@@ -1482,7 +1507,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp) //! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp)
inline PIDeque<T> & sort() { inline PIDeque<T> & sort() {
std::sort(begin(), end()); std::stable_sort(begin(), end());
return *this; return *this;
} }
@@ -1499,20 +1524,15 @@ public:
//! While the signature does not need to have const &, the function must not modify the objects passed to it. //! While the signature does not need to have const &, the function must not modify the objects passed to it.
//! The function must return `false` for identical elements, //! The function must return `false` for identical elements,
//! otherwise, it will lead to undefined program behavior and memory errors. //! otherwise, it will lead to undefined program behavior and memory errors.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort). //! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`. //! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется. //! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`. //! Для сравнения элементов используется функция сравнения `comp`.
//! Функция сравнения, возвращает `true` если первый аргумент меньше второго. //! Функция сравнения, возвращает `true` если первый аргумент меньше
//! Сигнатура функции сравнения должна быть эквивалентна следующей: //! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура
//! \code //! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для
//! bool comp(const T &a, const T &b); //! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция
//! \endcode //! [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort). Сложность сортировки `O(N·log(N))`.
//! Сигнатура не обязана содержать const &, однако, функция не может изменять переданные объекты.
//! Функция обязана возвращать `false` для одинаковых элементов,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code //! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3}; //! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;}); //! v.sort([](const int & a, const int & b){return a > b;});
@@ -1520,7 +1540,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a sort() //! \~\sa \a sort()
inline PIDeque<T> & sort(std::function<bool(const T & a, const T & b)> comp) { inline PIDeque<T> & sort(std::function<bool(const T & a, const T & b)> comp) {
std::sort(begin(), end(), comp); std::stable_sort(begin(), end(), comp);
return *this; return *this;
} }
@@ -1542,7 +1562,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a reversed() //! \~\sa \a reversed()
inline PIDeque<T> & reverse() { inline PIDeque<T> & reverse() {
size_t s2 = pid_size/2; const size_t s2 = pid_size / 2;
for (size_t i = 0; i < s2; ++i) { for (size_t i = 0; i < s2; ++i) {
piSwap<T>(pid_data[pid_start + i], pid_data[pid_start + pid_size - i - 1]); piSwap<T>(pid_data[pid_start + i], pid_data[pid_start + pid_size - i - 1]);
} }
@@ -1573,9 +1593,11 @@ public:
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым. //! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize() //! \~\sa \a resize()
inline PIDeque<T> & enlarge(ssize_t add_size, const T & e = T()) { inline PIDeque<T> & enlarge(ssize_t add_size, const T & e = T()) {
ssize_t ns = size_s() + add_size; const ssize_t ns = size_s() + add_size;
if (ns <= 0) clear(); if (ns <= 0)
else resize(size_t(ns), e); clear();
else
resize(size_t(ns), e);
return *this; return *this;
} }
@@ -1608,12 +1630,15 @@ public:
//! \endcode //! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere() //! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeAll(const T & e) { inline PIDeque<T> & removeAll(const T & e) {
for (size_t i = 0; i < pid_size; ++i) { ssize_t j = indexOf(e);
if (pid_data[i + pid_start] == e) { if (j != -1) {
remove(i); for (size_t i = j + 1; i < pid_size; ++i) {
--i; if (pid_data[i + pid_start] != e) {
pid_data[j++ + pid_start] = std::move(pid_data[i + pid_start]);
} }
} }
remove(j, pid_size - j);
}
return *this; return *this;
} }
@@ -1629,12 +1654,15 @@ public:
//! \endcode //! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere() //! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) { inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) {
for (size_t i = 0; i < pid_size; ++i) { ssize_t j = indexWhere(test);
if (test(pid_data[i + pid_start])) { if (j != -1) {
remove(i); for (size_t i = j + 1; i < pid_size; ++i) {
--i; if (!test(pid_data[i + pid_start])) {
pid_data[j++ + pid_start] = std::move(pid_data[i + pid_start]);
} }
} }
remove(j, pid_size - j);
}
return *this; return *this;
} }
@@ -1693,7 +1721,8 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIDeque<T> & push_back(std::initializer_list<T> init_list) { inline PIDeque<T> & push_back(std::initializer_list<T> init_list) {
size_t ps = pid_size; if (init_list.size() == 0) return *this;
const size_t ps = pid_size;
alloc_forward(pid_size + init_list.size()); alloc_forward(pid_size + init_list.size());
newT(pid_data + pid_start + ps, init_list.begin(), init_list.size()); newT(pid_data + pid_start + ps, init_list.begin(), init_list.size());
return *this; return *this;
@@ -1706,13 +1735,14 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIDeque<T> & push_back(const PIDeque<T> & v) { inline PIDeque<T> & push_back(const PIDeque<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG #ifndef NDEBUG
if (&v == this) { if (&v == this) {
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(&v != this); assert(&v != this);
size_t ps = pid_size; const size_t ps = pid_size;
alloc_forward(pid_size + v.pid_size); alloc_forward(pid_size + v.pid_size);
newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size); newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size);
return *this; return *this;
@@ -1835,7 +1865,9 @@ public:
//! \endcode //! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert() //! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIDeque<T> & push_front(const T & e) { inline PIDeque<T> & push_front(const T & e) {
insert(0, e); if (isEmpty()) return push_back(e);
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, e);
return *this; return *this;
} }
@@ -1846,7 +1878,9 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_front() //! \~\sa \a push_front()
inline PIDeque<T> & push_front(T && e) { inline PIDeque<T> & push_front(T && e) {
insert(0, std::move(e)); if (isEmpty()) return push_back(std::move(e));
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, std::move(e));
return *this; return *this;
} }
@@ -1861,10 +1895,7 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3} //! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode //! \endcode
//! \~\sa \a push_front() //! \~\sa \a push_front()
inline PIDeque<T> & push_front(const PIDeque<T> & v) { inline PIDeque<T> & push_front(const PIDeque<T> & v) { return insert(0, v); }
insert(0, v);
return *this;
}
//! \~english Appends the given elements to the begin of the array. //! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива. //! \~russian Добавляет элементы в начало массива.
@@ -1876,10 +1907,7 @@ public:
//! Добавляет элементы из //! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append() //! \~\sa \a append()
inline PIDeque<T> & push_front(std::initializer_list<T> init_list) { inline PIDeque<T> & push_front(std::initializer_list<T> init_list) { return insert(0, init_list); }
insert(0, init_list);
return *this;
}
//! \~english Appends the given element `e` to the begin of the array. //! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива. //! \~russian Добавляет элемент `e` в начало массива.
@@ -1955,7 +1983,8 @@ public:
//! \~\sa \a pop_front(), \a take_back(), \a take_front() //! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_back() { inline PIDeque<T> & pop_back() {
if (pid_size == 0) return *this; if (pid_size == 0) return *this;
resize(pid_size - 1); elementDelete(pid_data[pid_size + pid_start - 1]);
pid_size = pid_size - 1;
return *this; return *this;
} }
@@ -1976,7 +2005,9 @@ public:
//! \~\sa \a pop_back(), \a take_back(), \a take_front() //! \~\sa \a pop_back(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_front() { inline PIDeque<T> & pop_front() {
if (pid_size == 0) return *this; if (pid_size == 0) return *this;
remove(0); elementDelete(pid_data[pid_start]);
pid_start += 1;
pid_size -= 1;
return *this; return *this;
} }
@@ -1990,7 +2021,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() { inline T take_back() {
T e(back()); const T e(back());
pop_back(); pop_back();
return e; return e;
} }
@@ -2005,7 +2036,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() { inline T take_front() {
T e(front()); const T e(front());
pop_front(); pop_front();
return e; return e;
} }
@@ -2022,6 +2053,7 @@ public:
template<typename ST> template<typename ST>
inline PIDeque<ST> toType() const { inline PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size); PIDeque<ST> ret(pid_size);
ret.reserve(pid_size);
for (size_t i = 0; i < pid_size; ++i) { for (size_t i = 0; i < pid_size; ++i) {
ret[i] = ST(pid_data[i + pid_start]); ret[i] = ST(pid_data[i + pid_start]);
} }
@@ -2029,9 +2061,9 @@ public:
} }
//! \~english Returns a new array with all elements //! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `test`. //! that pass the test implemented by the provided function `bool test(const T & e)`.
//! \~russian Возвращает новый массив со всеми элементами, //! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `test`. //! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`.
//! \~\details //! \~\details
//! \~\code //! \~\code
//! PIDeque<int> v{3, 2, 5, 2, 7}; //! PIDeque<int> v{3, 2, 5, 2, 7};
@@ -2047,6 +2079,39 @@ public:
return ret; return ret;
} }
//! \~english Same as \a filter() but with `index` parameter in `test`.
//! \~russian Аналогично \a filter() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filter()
inline PIDeque<T> filterIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIDeque<T> ret;
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
if (test(i - pid_start, pid_data[i])) ret << pid_data[i];
}
return ret;
}
//! \~english Same as \a filter() but from end to begin (from right to left).
//! \~russian Аналогично \a filter() но от конца до начала (справа на лево).
//! \~\sa \a filter()
inline PIDeque<T> filterReverse(std::function<bool(const T & e)> test) const {
PIDeque<T> ret;
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
if (test(pid_data[i])) ret << pid_data[i];
}
return ret;
}
//! \~english Same as \a filterReverse() but with `index` parameter in `test`.
//! \~russian Аналогично \a filterReverse() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filterReverse()
inline PIDeque<T> filterReverseIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIDeque<T> ret;
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
if (test(i - pid_start, pid_data[i])) ret << pid_data[i];
}
return ret;
}
//! \~english Execute function `void f(const T & e)` for every element in array. //! \~english Execute function `void f(const T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива. //! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details //! \~\details
@@ -2087,6 +2152,63 @@ public:
return *this; return *this;
} }
//! \~english Same as \a forEach() but with `index` parameter in `f`.
//! \~russian Аналогично \a forEach() но с параметром индекса `index` в функции `f`.
//! \~\sa \a forEach()
inline void forEachIndexed(std::function<void(size_t index, const T & e)> f) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
f(i - pid_start, pid_data[i]);
}
}
//! \~english Same as \a forEachIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachIndexed()
inline PIDeque<T> & forEachIndexed(std::function<void(size_t index, T & e)> f) {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
f(i - pid_start, pid_data[i]);
}
return *this;
}
//! \~english Same as \a forEach() but from end to begin (from right to left).
//! \~russian Аналогично \a forEach() но от конца до начала (справа на лево).
//! \~\sa \a forEach()
inline void forEachReverse(std::function<void(const T & e)> f) const {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(pid_data[i]);
}
}
//! \~english Same as \a forEachReverse(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverse(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachReverse()
inline PIDeque<T> & forEachReverse(std::function<void(T & e)> f) {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(pid_data[i]);
}
return *this;
}
//! \~english Same as \a forEachIndexed() but from end to begin (from right to left).
//! \~russian Аналогично \a forEachIndexed() но от конца до начала (справа на лево).
//! \~\sa \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline void forEachReverseIndexed(std::function<void(size_t index, const T & e)> f) const {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(i - pid_start, pid_data[i]);
}
}
//! \~english Same as \a forEachReverseIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverseIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEachReverseIndexed(), \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline PIDeque<T> & forEachReverseIndexed(std::function<void(size_t index, T & e)> f) {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(i - pid_start, pid_data[i]);
}
return *this;
}
//! \~english Сreates a new array populated with the results //! \~english Сreates a new array populated with the results
//! of calling a provided function `ST f(const T & e)` on every element in the calling array. //! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции //! \~russian Создаёт новый массив с результатом вызова указанной функции
@@ -2096,23 +2218,78 @@ public:
//! once for each element in an array, in order, //! once for each element in an array, in order,
//! and constructs a new array from the results. //! and constructs a new array from the results.
//! \~russian Метод `map` вызывает переданную функцию `ST f(const T & e)` //! \~russian Метод `map` вызывает переданную функцию `ST f(const T & e)`
//! один раз для каждого элемента в порядке их появления //! один раз для каждого элемента в порядке их появления от начала к концу (слева на право)
//! и конструирует новый массив из результатов её вызова. //! и конструирует новый массив из результатов её вызова.
//! \~\code //! \~\code
//! PIDeque<int> v{1, 2, 3}; //! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);}); //! PIStringList sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; {"1", "2", "3"} //! piCout << sl; // {"1", "2", "3"}
//! \endcode //! \endcode
//! \~\sa \a forEach(), \a reduce() //! \~\sa \a forEach(), \a reduce()
template<typename ST> template<typename ST>
inline PIDeque<ST> map(std::function<ST(const T & e)> f) const { inline PIDeque<ST> map(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret; ret.reserve(pid_size); PIDeque<ST> ret;
ret.reserve(pid_size);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) { for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret << f(pid_data[i]); ret << f(pid_data[i]);
} }
return ret; return ret;
} }
//! \~english Same as \a map() but with `index` parameter in `f`.
//! \~russian Аналогично \a map() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.mapIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"0", "1", "2"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIDeque<ST> mapIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIDeque<ST> ret;
ret.reserve(pid_size);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret << f(i - pid_start, pid_data[i]);
}
return ret;
}
//! \~english Same as \a map() but from end to begin (from right to left).
//! \~russian Аналогично \a map() но от конца до начала (справа на лево).
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.mapReverse<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"3", "2", "1"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIDeque<ST> mapReverse(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret;
ret.reserve(pid_size);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret << f(pid_data[i]);
}
return ret;
}
//! \~english Same as \a mapReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a mapReverse() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.mapReverseIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"2", "1", "0"}
//! \endcode
//! \~\sa \a mapReverse()
template<typename ST>
inline PIDeque<ST> mapReverseIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIDeque<ST> ret;
ret.reserve(pid_size);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret << f(size_t(i) - pid_start, pid_data[i]);
}
return ret;
}
//! \~english Applies the function `ST f(const T & e, const ST & acc)` //! \~english Applies the function `ST f(const T & e, const ST & acc)`
//! to each element of the array (from left to right), returns one value. //! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)` //! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
@@ -2133,7 +2310,7 @@ public:
//! \param initial _optional_ Object used as the second argument //! \param initial _optional_ Object used as the second argument
//! when the `f` function is first called. //! when the `f` function is first called.
//! \~russian Метод reduce() выполняет функцию `f` //! \~russian Метод reduce() выполняет функцию `f`
//! один раз для каждого элемента, присутствующего в массиве. //! один раз для каждого элемента, присутствующего в массиве от начала к концу (слева на право).
//! Если при вызове reduce() передан аргумент `initial`, //! Если при вызове reduce() передан аргумент `initial`,
//! то при первом вызове функции `f` значение `acc` //! то при первом вызове функции `f` значение `acc`
//! будет равным значению `initial`. //! будет равным значению `initial`.
@@ -2153,7 +2330,7 @@ public:
//! int s = v.reduce<int>([](const int & e, const int & acc){return e + acc;}); //! int s = v.reduce<int>([](const int & e, const int & acc){return e + acc;});
//! piCout << s; // 15 //! piCout << s; // 15
//! \endcode //! \endcode
//! \~\sa \a forEach(), \a map() //! \~\sa \a reduceIndexed(), \a reduceReverse(), \a reduceReverseIndexed(), \a forEach(), \a map()
template<typename ST> template<typename ST>
inline ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const { inline ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial); ST ret(initial);
@@ -2163,6 +2340,42 @@ public:
return ret; return ret;
} }
//! \~english Same as \a reduce() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduce() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret = f(i - pid_start, pid_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduce() but from end to begin (from right to left).
//! \~russian Аналогично \a reduce() но от конца до начала (справа на лево).
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceReverse(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret = f(pid_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduceReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduceReverse() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduceReverse()
template<typename ST>
inline ST reduceReverseIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret = f(size_t(i) - pid_start, pid_data[i], ret);
}
return ret;
}
//! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array. //! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный. //! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details //! \~\details
@@ -2187,11 +2400,11 @@ public:
if (isEmpty()) return ret; if (isEmpty()) return ret;
#ifndef NDEBUG #ifndef NDEBUG
if (rows * cols != pid_size) { if (rows * cols != pid_size) {
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(rows * cols == pid_size); assert(rows * cols == pid_size);
ret.resize(rows); ret.expand(rows);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r] = PIDeque<T>(&(pid_data[r * cols]), cols); ret[r] = PIDeque<T>(&(pid_data[r * cols]), cols);
@@ -2199,7 +2412,7 @@ public:
} }
if (order == ReshapeByColumn) { if (order == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols); ret[r].expand(cols);
for (size_t c = 0; c < cols; c++) { for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c * rows + r]; ret[r][c] = pid_data[c * rows + r];
} }
@@ -2222,14 +2435,12 @@ public:
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6} //! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if< template<typename C, typename std::enable_if<std::is_same<T, PIDeque<C>>::value, int>::type = 0>
std::is_same<T, PIDeque<C>>::value
, int>::type = 0>
inline PIDeque<C> flatten(ReshapeOrder order = ReshapeByRow) const { inline PIDeque<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> ret; PIDeque<C> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
size_t rows = size(); const size_t rows = size();
size_t cols = at(0).size(); const size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
@@ -2265,155 +2476,259 @@ public:
//! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}} //! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if< template<typename C, typename std::enable_if<std::is_same<T, PIDeque<C>>::value, int>::type = 0>
std::is_same<T, PIDeque<C>>::value
, int>::type = 0>
inline PIDeque<PIDeque<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const { inline PIDeque<PIDeque<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> fl = flatten<C>(); PIDeque<C> fl = flatten<C>();
return fl.reshape(rows, cols, order); return fl.reshape(rows, cols, order);
} }
//! \~english Divides an array into a two-dimensional array using the separator `separator`.
//! \~russian Разделяет массив на двумерный массив с помощью разделителя`separator`.
//! \~\code
//! PIDeque<int> v{1, 2, 3, 99, 4, 5, 99, 6};
//! piCout << v.split(99); // {{1, 2, 3}, {4, 5}, {6}}
//! \endcode
//! \~\sa \a splitBySize()
inline PIDeque<PIDeque<T>> split(const T & separator) const {
PIDeque<PIDeque<T>> ret;
if (isEmpty()) return ret;
size_t start = 0;
ssize_t ci = indexOf(separator, start);
while (ci >= 0) {
ret << PIDeque<T>(pid_data + pid_start + start, ci - start);
start = ci + 1;
ci = indexOf(separator, start);
}
if (start < pid_size) {
ret << PIDeque<T>(pid_data + pid_start + start, pid_size - start);
}
return ret;
}
//! \~english Divides an array into a two-dimensional array in chunks of no more than `sz`.
//! \~russian Разделяет массив на двумерный массив по кускам не более чем `sz`.
//! \~\sa \a split()
inline PIDeque<PIDeque<T>> splitBySize(size_t sz) const {
PIDeque<PIDeque<T>> ret;
if (isEmpty() || sz == 0) return ret;
const size_t ch = pid_size / sz;
for (size_t i = 0; i < ch; ++i) {
ret << PIDeque<T>(pid_data + pid_start + sz * i, sz);
}
const size_t t = ch * sz;
if (t < pid_size) {
ret << PIDeque<T>(pid_data + pid_start + t, pid_size - t);
}
return ret;
}
//! \~english Cut sub-array of this array.
//! \~russian Вырезает подмассив, то есть кусок из текущего массива.
//! \~english
//! \param index - index of this array where sub-array starts
//! \param count - sub-array size
//! \~russian
//! \param index - индекс в текущем массиве, откуда начинётся подмассив
//! \param count - размер подмассива
//! \~\details
//! \~english
//! Index must be in range from `0` to `size()-1`.
//! If sub-array size more than this array size, than ends early.
//! \~russian
//! Индекс начала должен лежать в диапазоне от `0` до `size()-1`.
//! Если заданный размер подмассива превышает размер текущего массива,
//! то вернется подмассив меньшего размера (`size()-index-1`).
inline PIDeque<T> takeRange(size_t index, size_t count) {
PIDeque<T> ret;
if (index >= pid_size || count == 0) return ret;
if (index + count > pid_size) count = pid_size - index;
ret.alloc_forward(count);
memcpy(reinterpret_cast<void *>(ret.pid_data + ret.pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + index),
count * sizeof(T));
const size_t os = pid_size - index - count;
if (os <= index) {
if (os > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index),
reinterpret_cast<const void *>(pid_data + pid_start + index + count),
os * sizeof(T));
}
} else {
if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + count),
reinterpret_cast<const void *>(pid_data + pid_start),
index * sizeof(T));
}
pid_start += count;
}
pid_size -= count;
return ret;
}
private: private:
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;} inline void _reset() {
inline size_t asize(ssize_t s) { pid_size = 0;
if (s <= 0) return 0; pid_rsize = 0;
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) { pid_start = 0;
return pid_rsize + pid_rsize; pid_data = nullptr;
} }
size_t t = _PIContainerConstants<T>::minCountPoT();
size_t s_ = s - 1; template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
while (s_ >> t)
++t;
return (1 << t);
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s) PIINTROSPECTION_CONTAINER_USED(T, s)
for (size_t i = 0; i < s; ++i) for (size_t i = 0; i < s; ++i) {
elementNew(dst + i, src[i]); elementNew(dst + i, src[i]);
} }
template<typename T1 = T, typename std::enable_if< }
std::is_trivially_copyable<T1>::value
, int>::type = 0> template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s) PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy((void*)(dst), (const void*)(src), s * sizeof(T)); memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<const void *>(src), s * sizeof(T));
} }
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) { if (d != nullptr) {
for (size_t i = 0; i < sz; ++i) { for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
} }
} }
} }
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
} }
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
, int>::type = 0> inline void elementNew(T * to, const T & from) {
inline void elementNew(T * to, const T & from) {new(to)T(from);} new (to) T(from);
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {new(to)T(std::move(from));}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {(*to) = from;}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {(*to) = std::move(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {from.~T();}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {}
inline void dealloc() {
if ((uchar*)pid_data != 0) free((uchar*)pid_data);
pid_data = 0;
} }
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
new (to) T(std::move(from));
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {
(*to) = from;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
(*to) = std::move(from);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementDelete(T & from) {
from.~T();
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementDelete(T & from) {}
inline void dealloc() {
if (pid_data != nullptr) {
free(reinterpret_cast<void *>(pid_data));
pid_data = nullptr;
}
}
inline void checkMove() { inline void checkMove() {
if (pid_size >= 4) { if (pid_size >= 4) {
if (pid_size < pid_rsize / 6) { if (pid_size < pid_rsize / 6) {
if (pid_start < (pid_size + pid_size) || ssize_t(pid_start) > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) { if (pid_start < (pid_size * 2) || ssize_t(pid_start) > (ssize_t(pid_rsize) - (ssize_t(pid_size) * 2))) {
size_t ns = (pid_rsize - pid_size) / 2; size_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) { if (pid_start != ns) {
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + ns),
reinterpret_cast<const void *>(pid_data + pid_start),
pid_size * sizeof(T));
pid_start = ns; pid_start = ns;
} }
} }
} }
} else { } else {
size_t ns = (pid_rsize - pid_size) / 2; const size_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) { if (pid_start != ns) {
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T)); memmove(reinterpret_cast<void *>(pid_data + ns),
reinterpret_cast<const void *>(pid_data + pid_start),
pid_size * sizeof(T));
pid_start = ns; pid_start = ns;
} }
} }
} }
inline void alloc_forward(size_t new_size) { // direction == true -> alloc forward
inline void alloc_forward(size_t new_size) {
if (pid_start + new_size <= pid_rsize) { if (pid_start + new_size <= pid_rsize) {
pid_size = new_size; pid_size = new_size;
checkMove(); if (pid_start > 0) checkMove();
return; return;
} }
pid_size = new_size; pid_size = new_size;
size_t as = asize(pid_start + new_size); const size_t new_rsize = _PIContainerConstants<T>::calcNewSize(pid_rsize, pid_start + new_size);
if (as != pid_rsize) { if (new_rsize != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize)) PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T))); T * new_data = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), new_rsize * sizeof(T)));
#ifndef NDEBUG #ifndef NDEBUG
if (!p_d) { if (!new_data) {
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(p_d); assert(new_data);
pid_data = p_d; pid_data = new_data;
pid_rsize = as; pid_rsize = new_rsize;
} }
} }
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
size_t as; inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) {
if (ssize_t(pid_start) + start_offset < 0) { const size_t new_rsize =
as = asize(pid_rsize - start_offset); ssize_t(pid_start) + start_offset < 0 ? _PIContainerConstants<T>::calcNewSize(pid_rsize, pid_rsize - start_offset) : pid_rsize;
} else { if (new_rsize > pid_rsize) {
as = pid_rsize; T * tmp_data = reinterpret_cast<T *>(malloc(new_rsize * sizeof(T)));
} const size_t new_start = pid_start + new_rsize - pid_rsize;
if (as > pid_rsize) {
T * td = (T*)(malloc(as * sizeof(T)));
size_t ns = pid_start + as - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize)) PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
if (pid_rsize > 0 && pid_data != 0) { if (pid_rsize > 0 && pid_data) {
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T)); memcpy(reinterpret_cast<void *>(tmp_data + new_start),
reinterpret_cast<const void *>(pid_data + pid_start),
pid_size * sizeof(T));
dealloc(); dealloc();
} }
pid_data = td; pid_data = tmp_data;
pid_rsize = as; pid_rsize = new_rsize;
pid_start = ns; pid_start = new_start;
} }
pid_start += start_offset; pid_start += start_offset;
pid_size = new_size; pid_size = new_size;
checkMove(); checkMove();
} }
T * pid_data; inline void expand(size_t new_size, const T & e = T()) {
size_t pid_size; const size_t os = pid_size;
size_t pid_rsize; alloc_forward(new_size);
size_t pid_start; PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, e);
}
}
inline void expand(size_t new_size, std::function<T(size_t i)> f) {
const size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f(i));
}
}
T * pid_data = nullptr;
size_t pid_size = 0;
size_t pid_rsize = 0;
size_t pid_start = 0;
}; };
@@ -2451,7 +2766,9 @@ inline PICout operator <<(PICout s, const PIDeque<T> & v) {
} }
template<typename T> template<typename T>
inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {f.swap(s);} inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {
f.swap(s);
}
#endif // PIDEQUE_H #endif // PIDEQUE_H

View File

@@ -1,190 +0,0 @@
/** \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.
* \fn void PIMapIterator::reset()
* \brief Reset iterator to initial position.
* */

View File

@@ -1,6 +1,6 @@
//! \addtogroup Containers //! \addtogroup Containers
//! \{ //! \{
//! \file pideque.h //! \file pimap.h
//! \brief //! \brief
//! \~english Declares \a PIMap //! \~english Declares \a PIMap
//! \~russian Объявление \a PIMap //! \~russian Объявление \a PIMap
@@ -34,15 +34,19 @@
#ifndef PIMAP_H #ifndef PIMAP_H
#define PIMAP_H #define PIMAP_H
#include "pivector.h"
#include "pideque.h" #include "pideque.h"
#include "pipair.h" #include "pipair.h"
#include "pivector.h"
template <typename Key, typename T> class PIMapIteratorConst; template<typename Key, typename T>
template <typename Key, typename T> class PIMapIteratorConstReverse; class PIMapIteratorConst;
template <typename Key, typename T> class PIMapIterator; template<typename Key, typename T>
template <typename Key, typename T> class PIMapIteratorReverse; class PIMapIteratorConstReverse;
template<typename Key, typename T>
class PIMapIterator;
template<typename Key, typename T>
class PIMapIteratorReverse;
//! \addtogroup Containers //! \addtogroup Containers
@@ -76,14 +80,19 @@ template <typename Key, typename T> class PIMapIteratorReverse;
//! и если такого эелемента не было, то он будет создан. //! и если такого эелемента не было, то он будет создан.
template<typename Key, typename T> template<typename Key, typename T>
class PIMap { class PIMap {
template <typename Key1, typename T1> friend class PIMapIteratorConst; template<typename Key1, typename T1>
template <typename Key1, typename T1> friend class PIMapIteratorConstReverse; friend class PIMapIteratorConst;
template <typename Key1, typename T1> friend class PIMapIterator; template<typename Key1, typename T1>
template <typename Key1, typename T1> friend class PIMapIteratorReverse; friend class PIMapIteratorConstReverse;
template<typename Key1, typename T1>
friend class PIMapIterator;
template<typename Key1, typename T1>
friend class PIMapIteratorReverse;
template<typename P, typename Key1, typename T1> template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMap<Key1, T1> & v); friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMap<Key1, T1> & v);
template<typename P, typename Key1, typename T1> template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key1, T1> & v); friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key1, T1> & v);
public: public:
typedef T mapped_type; typedef T mapped_type;
typedef Key key_type; typedef Key key_type;
@@ -91,15 +100,15 @@ public:
//! \~english Constructs an empty map. //! \~english Constructs an empty map.
//! \~russian Создает пустой словарь. //! \~russian Создает пустой словарь.
PIMap() {} inline PIMap() {}
//! \~english Copy constructor. //! \~english Copy constructor.
//! \~russian Копирующий конструктор. //! \~russian Копирующий конструктор.
PIMap(const PIMap<Key, T> & other) {*this = other;} inline PIMap(const PIMap<Key, T> & other): pim_content(other.pim_content), pim_index(other.pim_index) {}
//! \~english Move constructor. //! \~english Move constructor.
//! \~russian Перемещающий конструктор. //! \~russian Перемещающий конструктор.
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {} inline PIMap(PIMap<Key, T> && other): pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
//! \~english Contructs map from //! \~english Contructs map from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list). //! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
@@ -108,9 +117,9 @@ public:
//! \~\details //! \~\details
//! \~\code //! \~\code
//! PIMap <int, PIString> m{{1, "a"}, {2, "b"}}; //! PIMap <int, PIString> m{{1, "a"}, {2, "b"}};
//! piCout << m; // {1, 2, 3} //! piCout << m; // {1: a, 2: b}
//! \endcode //! \endcode
PIMap(std::initializer_list<std::pair<Key, T>> init_list) { inline PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
for (auto i: init_list) { for (auto i: init_list) {
insert(std::get<0>(i), std::get<1>(i)); insert(std::get<0>(i), std::get<1>(i));
} }
@@ -118,7 +127,7 @@ public:
//! \~english Assign operator. //! \~english Assign operator.
//! \~russian Оператор присваивания. //! \~russian Оператор присваивания.
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) { inline PIMap<Key, T> & operator=(const PIMap<Key, T> & other) {
if (this == &other) return *this; if (this == &other) return *this;
clear(); clear();
pim_content = other.pim_content; pim_content = other.pim_content;
@@ -128,17 +137,19 @@ public:
//! \~english Assign move operator. //! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания. //! \~russian Оператор перемещающего присваивания.
PIMap<Key, T> & operator =(PIMap<Key, T> && other) { inline PIMap<Key, T> & operator=(PIMap<Key, T> && other) {
swap(other); swap(other);
return *this; return *this;
} }
class iterator { class iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
iterator(): parent(nullptr), pos(0) {} iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); } const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
@@ -156,10 +167,12 @@ public:
class reverse_iterator { class reverse_iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
reverse_iterator(): parent(nullptr), pos(0) {} reverse_iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); } const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
@@ -177,10 +190,12 @@ public:
class const_iterator { class const_iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
const_iterator(): parent(nullptr), pos(0) {} const_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); } const value_type operator*() const { return parent->_pair(pos); }
@@ -196,10 +211,12 @@ public:
class const_reverse_iterator { class const_reverse_iterator {
friend class PIMap<Key, T>; friend class PIMap<Key, T>;
private: private:
const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {} const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent; const PIMap<Key, T> * parent;
ssize_t pos; ssize_t pos;
public: public:
const_reverse_iterator(): parent(nullptr), pos(0) {} const_reverse_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); } const value_type operator*() const { return parent->_pair(pos); }
@@ -212,75 +229,133 @@ public:
}; };
iterator begin() {return iterator(this, 0);} //! \~english Iterator to the first element.
//! \~russian Итератор на первый элемент.
inline iterator begin() { return iterator(this, 0); }
iterator end() {return iterator(this, size());} //! \~english Iterator to the element following the last element.
//! \~russian Итератор на элемент, следующий за последним элементом.
inline iterator end() { return iterator(this, size()); }
const_iterator begin() const {return const_iterator(this, 0);} inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, size()); }
const_iterator end() const {return const_iterator(this, size());} //! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
inline reverse_iterator rbegin() { return reverse_iterator(this, size() - 1); }
const_iterator constBegin() const {return const_iterator(this, 0);} //! \~english Returns a reverse iterator to the element.
//! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент,
//! следующий за последним элементом.
inline reverse_iterator rend() { return reverse_iterator(this, -1); }
const_iterator constEnd() const {return const_iterator(this, size());} inline const_reverse_iterator rbegin() const { return const_reverse_iterator(this, size() - 1); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(this, -1); }
reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
reverse_iterator rend() {return reverse_iterator(this, -1);}
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}
//! \relatesalso PIMapIteratorConst //! \relatesalso PIMapIteratorConst
PIMapIteratorConst<Key, T> makeIterator() const {return PIMapIteratorConst<Key, T>(*this);} inline PIMapIteratorConst<Key, T> makeIterator() const { return PIMapIteratorConst<Key, T>(*this); }
//! \relatesalso PIMapIterator //! \relatesalso PIMapIterator
PIMapIterator<Key, T> makeIterator() {return PIMapIterator<Key, T>(*this);} inline PIMapIterator<Key, T> makeIterator() { return PIMapIterator<Key, T>(*this); }
//! \relatesalso PIMapIteratorConstReverse //! \relatesalso PIMapIteratorConstReverse
PIMapIteratorConstReverse<Key, T> makeReverseIterator() const {return PIMapIteratorConstReverse<Key, T>(*this);} inline PIMapIteratorConstReverse<Key, T> makeReverseIterator() const { return PIMapIteratorConstReverse<Key, T>(*this); }
//! \relatesalso PIMapIteratorReverse //! \relatesalso PIMapIteratorReverse
PIMapIteratorReverse<Key, T> makeReverseIterator() {return PIMapIteratorReverse<Key, T>(*this);} inline PIMapIteratorReverse<Key, T> makeReverseIterator() { return PIMapIteratorReverse<Key, T>(*this); }
size_t size() const {return pim_content.size();} //! \~english Number of elements in the container.
//! \~russian Количество элементов массива.
//! \~\sa \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t size() const { return pim_content.size(); }
int size_s() const {return pim_content.size_s();} //! \~english Number of elements in the container as signed value.
//! \~russian Количество элементов массива в виде знакового числа.
//! \~\sa \a size(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline int size_s() const { return pim_content.size_s(); }
size_t length() const {return pim_content.size();} //! \~english Same as \a size().
//! \~russian Синоним \a size().
//! \~\sa \a size(), \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t length() const { return pim_content.size(); }
bool isEmpty() const {return (pim_content.size() == 0);} //! \~english Checks if the container has no elements.
//! \~russian Проверяет пуст ли массив.
//! \~\return
//! \~english **true** if the container is empty, **false** otherwise
//! \~russian **true** если массив пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isEmpty() const { return (pim_content.size() == 0); }
bool isNotEmpty() const {return (pim_content.size() > 0);} //! \~english Checks if the container has elements.
//! \~russian Проверяет не пуст ли массив.
//! \~\return
//! \~english **true** if the container is not empty, **false** otherwise
//! \~russian **true** если массив не пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isNotEmpty() const { return (pim_content.size() > 0); }
T & operator [](const Key & key) {
//! \~english Full access to element key `key`.
//! \~russian Полный доступ к элементу по ключу `key`.
//! \~\details
//! \~english If the map contains no item with key `key`,
//! the function inserts a default-constructed value into the map with key `key`,
//! and returns a reference to it.
//! \~russian Если элемента с таким ключом `key` не существует,
//! то он будет создан конструктором по умолчанию и добавлен в массив
//! по ключу `key`, а затем возвращена ссылка на этот новый элемент.
//! \~\code
//! PIMap <PIString, int> m;
//! m["огурец"] = 500;
//! piCout << m; // {огурец: 500}
//! m["лук"] = 25;
//! piCout << m; // {огурец: 500, лук: 25}
//! m["огурец"] = 350;
//! piCout << m; // {огурец: 350, лук: 25}
//! \endcode
//! \~\sa \a insert(), \a value(), \a key()
inline T & operator[](const Key & key) {
bool f(false); bool f(false);
ssize_t i = _find(key, f); const ssize_t i = _find(key, f);
if (f) return pim_content[pim_index[i].index]; if (f) return _value(i);
pim_content.push_back(T()); pim_content.push_back(T());
pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
return pim_content.back(); return pim_content.back();
} }
T at(const Key & key) const {return value(key);}
T take(const Key & key) const { //! \~english Read only access to element by `key`.
//! \~russian Доступ исключительно на чтение к элементу по ключу `key`.
//! \~\note
//! \~english Element with key `key` must exists,
//! otherwise it will lead to undefined program behavior and memory errors.
//! \~russian Элемент по ключу `key` должен существовать,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! \~\sa \a operator[](), \a value(), \a key()
inline const T & at(const Key & key) const {
bool f(false); bool f(false);
ssize_t i = _find(key, f); const ssize_t i = _find(key, f);
if (!f) return T(); return _value(i);
T ret(pim_content[pim_index[i].index]); }
//! \~english Remove element with key `key` from the array and return it.
//! \~russian Удаляет элемент с ключом `key` из массива и возвращает его.
inline T take(const Key & key, const T & default_ = T()) {
bool f(false);
const ssize_t i = _find(key, f);
if (!f) return default_;
const T ret = _value(i);
_remove(i); _remove(i);
return ret; return ret;
} }
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) { //! \~english Inserts all elements in array `other` to this array with overwrite.
//! \~russian Вставляет все элементы `other` этот массив с перезаписью.
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
#ifndef NDEBUG #ifndef NDEBUG
if (&other == this) { if (&other == this) {
printf("error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
} }
#endif #endif
assert(&other != this); assert(&other != this);
@@ -300,96 +375,139 @@ public:
return *this; return *this;
} }
bool operator ==(const PIMap<Key, T> & t) const { //! \~english Compare operator with array `m`.
return (pim_content == t.pim_content && pim_index == t.pim_index); //! \~russian Оператор сравнения с массивом `m`.
} inline bool operator==(const PIMap<Key, T> & m) const { return (pim_content == m.pim_content && pim_index == m.pim_index); }
bool operator !=(const PIMap<Key, T> & t) const {
return (pim_content != t.pim_content || pim_index != t.pim_index); //! \~english Compare operator with array `m`.
} //! \~russian Оператор сравнения с массивом `m`.
bool contains(const Key & key) const { inline bool operator!=(const PIMap<Key, T> & m) const { return (pim_content != m.pim_content || pim_index != m.pim_index); }
bool f(false); _find(key, f);
//! \~english Tests if element with key `key` exists in the array.
//! \~russian Проверяет наличие элемента с ключом `key` в массиве.
inline bool contains(const Key & key) const {
bool f(false);
_find(key, f);
return f; return f;
} }
bool containsValue(const T & value) const { //! \~english Tests if element with value `value` exists in the array.
return pim_content.contains(value); //! \~russian Проверяет наличие элемента со значением `value` в массиве.
} inline bool containsValue(const T & value) const { return pim_content.contains(value); }
PIMap<Key, T> & reserve(size_t new_size) { //! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
inline PIMap<Key, T> & reserve(size_t new_size) {
pim_content.reserve(new_size); pim_content.reserve(new_size);
pim_index.reserve(new_size); pim_index.reserve(new_size);
return *this; return *this;
} }
PIMap<Key, T> & remove(const Key & key) { //! \~english Remove element with key `key` from the array.
//! \~russian Удаляет элемент с ключом `key` из массива.
inline PIMap<Key, T> & remove(const Key & key) {
bool f(false); bool f(false);
ssize_t i = _find(key, f); const ssize_t i = _find(key, f);
if (f) _remove(i); if (f) _remove(i);
return *this; return *this;
} }
PIMap<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> test) { //! \~english Remove all elements in the array
//! passes the test implemented by the provided function `test`.
//! \~russian Удаляет все элементы, удовлетворяющие условию,
//! заданному в передаваемой функции `test`.
inline PIMap<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> test) {
for (int i = 0; i < pim_index.size_s(); ++i) { for (int i = 0; i < pim_index.size_s(); ++i) {
if (pim_index[i].key, pim_content[pim_index[i].index]) { const auto & mi(pim_index[i]);
if (test(mi.key, pim_content[mi.index])) {
_remove(i); _remove(i);
--i; --i;
} }
} }
return *this;
} }
PIMap<Key, T> & erase(const Key & key) {return remove(key);} //! \~english Same as \a remove().
//! \~russian Синоним функции \a remove().
inline PIMap<Key, T> & erase(const Key & key) { return remove(key); }
PIMap<Key, T> & clear() {
//! \~english Clear array, remove all elements.
//! \~russian Очищает массив, удаляет все элементы.
//! \~\details
//! \~\note
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
inline PIMap<Key, T> & clear() {
pim_content.clear(); pim_content.clear();
pim_index.clear(); pim_index.clear();
return *this; return *this;
} }
void swap(PIMap<Key, T> & other) { //! \~english Swaps array `v` other with this array.
//! \~russian Меняет местами массив `v` с этим массивом.
//! \~\details
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIMap<Key, T> & other) {
pim_content.swap(other.pim_content); pim_content.swap(other.pim_content);
pim_index.swap(other.pim_index); pim_index.swap(other.pim_index);
} }
PIMap<Key, T> & insert(const Key & key, const T & value) { //! \~english Inserts value `value` with key `key` in the array.
//! \~russian Вставляет значение `value` с ключом `key` в массив.
//! \~\details
//! \~english If an element with the key `key` already exists, it will be overwritten with the value `value`.
//! \~russian Если элемент с ключом `key` уже существует, то он будет перезаписан на значение `value`.
inline PIMap<Key, T> & insert(const Key & key, const T & value) {
bool f(false); bool f(false);
ssize_t i = _find(key, f); const ssize_t i = _find(key, f);
if (f) { if (f) {
pim_content[pim_index[i].index] = value; _value(i) = value;
} else { } else {
pim_content.push_back(value); pim_content.push_back(value);
pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
} }
return *this; return *this;
} }
PIMap<Key, T> & insert(const Key & key, T && value) {
inline PIMap<Key, T> & insert(const Key & key, T && value) {
bool f(false); bool f(false);
ssize_t i = _find(key, f); const ssize_t i = _find(key, f);
if (f) { if (f) {
pim_content[pim_index[i].index] = std::move(value); _value(i) = std::move(value);
} else { } else {
pim_content.push_back(std::move(value)); pim_content.push_back(std::move(value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
} }
return *this; return *this;
} }
PIMap<Key, T> & insert(const PIPair<Key, T> & pair) {
//! \~english Inserts value `pair` in the array.
//! \~russian Вставляет пару `pair` в массив.
//! \~\details
//! \~english The first element of the pair is the key, and the second is the value.
//! \~russian Первый элемент пары является ключом, а второй значением.
inline PIMap<Key, T> & insert(const PIPair<Key, T> & pair) {
bool f(false); bool f(false);
ssize_t i = _find(pair.first, f); const ssize_t i = _find(pair.first, f);
if (f) { if (f) {
pim_content[pim_index[i].index] = pair.second; _value(i) = pair.second;
} else { } else {
pim_content.push_back(pair.second); pim_content.push_back(pair.second);
pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1)); pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1));
} }
return *this; return *this;
} }
PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
inline PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
bool f(false); bool f(false);
Key k(std::move(pair.first)); Key k(std::move(pair.first));
ssize_t i = _find(k, f); const ssize_t i = _find(k, f);
if (f) { if (f) {
pim_content[pim_index[i].index] = std::move(pair.second); _value(i) = std::move(pair.second);
} else { } else {
pim_content.push_back(std::move(pair.second)); pim_content.push_back(std::move(pair.second));
pim_index.insert(i, MapIndex(k, pim_content.size() - 1)); pim_index.insert(i, MapIndex(k, pim_content.size() - 1));
@@ -397,25 +515,38 @@ public:
return *this; return *this;
} }
T value(const Key & key, const T & default_ = T()) const { //! \~english Returns the value of the element by the key `key`
//! or `default_` if there is no such element.
//! \~russian Возвращает значение элемента по ключу `key`
//! или `default_` если такого элемента нет.
inline T value(const Key & key, const T & default_ = T()) const {
bool f(false); bool f(false);
ssize_t i = _find(key, f); const ssize_t i = _find(key, f);
if (!f) return default_; if (!f) return default_;
return pim_content[pim_index[i].index]; return _value(i);
} }
PIVector<T> values() const {return pim_content;} //! \~english Returns an array of values of all elements
//! \~russian Возвращает массив значений всех эелметнов
inline PIVector<T> values() const { return pim_content; }
Key key(const T & value_, const Key & default_ = Key()) const { //! \~english Returns the key of the first element
//! whose value matches `value` or `default_` if there is no such element.
//! \~russian Возвращает ключ первого элемента, значение которого
//! совпадает с `value` или `default_` если такого элемента нет.
inline Key key(const T & value, const Key & default_ = Key()) const {
for (int i = 0; i < pim_index.size_s(); ++i) { for (int i = 0; i < pim_index.size_s(); ++i) {
if (pim_content[pim_index[i].index] == value_) { const auto & mi(pim_index[i]);
return pim_index[i].key; if (pim_content[mi.index] == value) {
return mi.key;
} }
} }
return default_; return default_;
} }
PIVector<Key> keys() const { //! \~english Returns an array of keys of all elements
//! \~russian Возвращает массив ключей всех элементов
inline PIVector<Key> keys() const {
PIVector<Key> ret; PIVector<Key> ret;
ret.reserve(pim_index.size()); ret.reserve(pim_index.size());
for (int i = 0; i < pim_index.size_s(); ++i) { for (int i = 0; i < pim_index.size_s(); ++i) {
@@ -424,31 +555,62 @@ public:
return ret; return ret;
} }
void forEach(std::function<void(const Key & key, const T & value)> f) const { //! \~english Execute function `void f(const Key & key, const T & value)` for every element in array.
//! \~russian Выполняет функцию `void f(const Key & key, const T & value)` для каждого элемента массива.
inline void forEach(std::function<void(const Key & key, const T & value)> f) const {
for (int i = 0; i < pim_index.size_s(); ++i) { for (int i = 0; i < pim_index.size_s(); ++i) {
f(pim_index[i].key, pim_content[pim_index[i].index]); const auto & mi(pim_index[i]);
f(mi.key, pim_content[mi.index]);
} }
} }
//! \~english Сreates a new map PIMap<Key2, T2> populated with the results
//! of calling a provided function `PIPair<Key2, T2> f(const Key & key, const T & value)` on every element in the calling array.
//! \~russian Создаёт новый словарь PIMap<Key2, T2> с результатом вызова указанной функции
//! `PIPair<Key2, T2> f(const Key & key, const T & value)` для каждого элемента массива.
template<typename Key2, typename T2> template<typename Key2, typename T2>
inline PIMap<Key2, T2> map(std::function<PIPair<Key2, T2>(const Key & key, const T & value)> f) const { inline PIMap<Key2, T2> map(std::function<PIPair<Key2, T2>(const Key & key, const T & value)> f) const {
PIMap<Key2, T2> ret; ret.reserve(size()); PIMap<Key2, T2> ret;
ret.reserve(size());
for (int i = 0; i < pim_index.size_s(); ++i) { for (int i = 0; i < pim_index.size_s(); ++i) {
ret.insert(f(pim_index[i].key, pim_content[pim_index[i].index])); const auto & mi(pim_index[i]);
ret.insert(f(mi.key, pim_content[mi.index]));
} }
return ret; return ret;
} }
//! \~english Сreates a new array PIVector<ST> populated with the results
//! of calling a provided function `ST f(const Key & key, const T & value)` on every element in the calling array.
//! \~russian Создаёт новый массив PIVector<ST> с результатом вызова указанной функции
//! `ST f(const Key & key, const T & value)` для каждого элемента массива.
template<typename ST> template<typename ST>
inline PIVector<ST> map(std::function<ST(const Key & key, const T & value)> f) const { inline PIVector<ST> map(std::function<ST(const Key & key, const T & value)> f) const {
PIVector<ST> ret; ret.reserve(size()); PIVector<ST> ret;
ret.reserve(size());
for (int i = 0; i < pim_index.size_s(); ++i) { for (int i = 0; i < pim_index.size_s(); ++i) {
ret << f(pim_index[i].key, pim_content[pim_index[i].index]); const auto & mi(pim_index[i]);
ret << f(mi.key, pim_content[mi.index]);
} }
return ret; return ret;
} }
private: //! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `bool test(const Key & key, const T & value)`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const Key & key, const T & value)`.
inline PIMap<Key, T> filter(std::function<bool(const Key & key, const T & value)> test) const {
PIMap<Key, T> ret;
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
const auto & v(pim_content[mi.index]);
if (test(mi.key, v)) {
ret.insert(mi.key, v);
}
}
return ret;
}
protected:
struct MapIndex { struct MapIndex {
MapIndex(const Key & k = Key(), size_t i = 0): key(k), index(i) {} MapIndex(const Key & k = Key(), size_t i = 0): key(k), index(i) {}
MapIndex(Key && k, size_t i = 0): key(std::move(k)), index(i) {} MapIndex(Key && k, size_t i = 0): key(std::move(k)), index(i) {}
@@ -465,19 +627,28 @@ private:
template<typename P, typename Key1, typename T1> template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v); friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
ssize_t _binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const { PIVector<T> pim_content;
ssize_t mid; PIDeque<MapIndex> pim_index;
private:
inline ssize_t _binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
ssize_t mid = 0;
while (first <= last) { while (first <= last) {
mid = (first + last) / 2; mid = (first + last) / 2;
if (key > pim_index[mid].key) first = mid + 1; if (key > pim_index[mid].key)
else if (key < pim_index[mid].key) last = mid - 1; first = mid + 1;
else {found = true; return mid;} else if (key < pim_index[mid].key)
last = mid - 1;
else {
found = true;
return mid;
}
} }
found = false; found = false;
return first; return first;
} }
ssize_t _find(const Key & k, bool & found) const { inline ssize_t _find(const Key & k, bool & found) const {
if (pim_index.isEmpty()) { if (pim_index.isEmpty()) {
found = false; found = false;
return 0; return 0;
@@ -485,8 +656,8 @@ private:
return _binarySearch(0, pim_index.size_s() - 1, k, found); return _binarySearch(0, pim_index.size_s() - 1, k, found);
} }
void _remove(ssize_t index) { inline void _remove(ssize_t index) {
size_t ci = pim_index[index].index, bi = pim_index.size() - 1; const size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
pim_index.remove(index); pim_index.remove(index);
for (size_t i = 0; i < pim_index.size(); ++i) { for (size_t i = 0; i < pim_index.size(); ++i) {
if (pim_index[i].index == bi) { if (pim_index[i].index == bi) {
@@ -498,22 +669,19 @@ private:
pim_content.resize(pim_index.size()); pim_content.resize(pim_index.size());
} }
const value_type _pair(ssize_t index) const { inline const value_type _pair(ssize_t index) const {
if (index < 0 || index >= pim_index.size_s()) return value_type(); if (index < 0 || index >= pim_index.size_s()) return value_type();
return value_type(pim_index[index].key, pim_content[pim_index[index].index]); const auto & mi(pim_index[index]);
return value_type(mi.key, pim_content[mi.index]);
} }
Key & _key(ssize_t index) {return pim_index[index].key;} inline Key & _key(ssize_t index) { return pim_index[index].key; }
const Key & _key(ssize_t index) const {return pim_index[index].key;} inline const Key & _key(ssize_t index) const { return pim_index[index].key; }
T & _value(ssize_t index) {return pim_content[pim_index[index].index];} inline T & _value(ssize_t index) { return pim_content[pim_index[index].index]; }
const T & _value(ssize_t index) const {return pim_content[pim_index[index].index];} inline const T & _value(ssize_t index) const { return pim_content[pim_index[index].index]; }
PIVector<T> pim_content;
PIDeque<MapIndex> pim_index;
}; };
@@ -548,30 +716,25 @@ private:
template<typename Key, typename T> template<typename Key, typename T>
class PIMapIteratorConst { class PIMapIteratorConst {
typedef PIMap<Key, T> MapType; typedef PIMap<Key, T> MapType;
public: public:
PIMapIteratorConst(const PIMap<Key, T> & map): m(map), pos(-1) {} inline PIMapIteratorConst(const PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key. //! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента. //! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value() //! \~\sa \a value()
const Key & key() const { inline const Key & key() const { return m._key(pos); }
return m._key(pos);
}
//! \~english Returns current value. //! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента. //! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key() //! \~\sa \a key()
const T & value() const { inline const T & value() const { return m._value(pos); }
return m._value(pos);
}
//! \~english Returns true if iterator can jump to next entry //! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу. //! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next() //! \~\sa \a next()
inline bool hasNext() const { inline bool hasNext() const { return pos < (m.size_s() - 1); }
return pos < (m.size_s() - 1);
}
//! \~english Jump to next entry and return true if new position is valid. //! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует. //! \~russian Переходит к следующему элементу и возвращает true если он существует.
@@ -584,9 +747,8 @@ public:
//! \~english Reset iterator to initial position. //! \~english Reset iterator to initial position.
//! \~russian Переходит на начало. //! \~russian Переходит на начало.
//! \~\sa \a next() //! \~\sa \a next()
inline void reset() { inline void reset() { pos = -1; }
pos = -1;
}
private: private:
const MapType & m; const MapType & m;
ssize_t pos; ssize_t pos;
@@ -624,29 +786,24 @@ private:
template<typename Key, typename T> template<typename Key, typename T>
class PIMapIteratorConstReverse { class PIMapIteratorConstReverse {
typedef PIMap<Key, T> MapType; typedef PIMap<Key, T> MapType;
public: public:
PIMapIteratorConstReverse(const PIMap<Key, T> & map): m(map), pos(m.size_s()) {} inline PIMapIteratorConstReverse(const PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key. //! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента. //! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value() //! \~\sa \a value()
const Key & key() const { inline const Key & key() const { return m._key(pos); }
return m._key(pos);
}
//! \~english Returns current value. //! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента. //! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key() //! \~\sa \a key()
const T & value() const { inline const T & value() const { return m._value(pos); }
return m._value(pos);
}
//! \~english Returns true if iterator can jump to next entry //! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу. //! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next() //! \~\sa \a next()
inline bool hasNext() const { inline bool hasNext() const { return pos > 0; }
return pos > 0;
}
//! \~english Jump to next entry and return true if new position is valid. //! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует. //! \~russian Переходит к следующему элементу и возвращает true если он существует.
@@ -659,9 +816,8 @@ public:
//! \~english Reset iterator to initial position. //! \~english Reset iterator to initial position.
//! \~russian Переходит на начало. //! \~russian Переходит на начало.
//! \~\sa \a next() //! \~\sa \a next()
inline void reset() { inline void reset() { pos = m.size_s(); }
pos = m.size_s();
}
private: private:
const MapType & m; const MapType & m;
ssize_t pos; ssize_t pos;
@@ -700,29 +856,24 @@ private:
template<typename Key, typename T> template<typename Key, typename T>
class PIMapIterator { class PIMapIterator {
typedef PIMap<Key, T> MapType; typedef PIMap<Key, T> MapType;
public: public:
PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {} inline PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key. //! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента. //! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value() //! \~\sa \a value()
const Key & key() const { inline const Key & key() const { return m._key(pos); }
return m._key(pos);
}
//! \~english Returns current value. //! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента. //! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key() //! \~\sa \a key()
T & value() { inline T & value() { return m._value(pos); }
return m._value(pos);
}
//! \~english Returns true if iterator can jump to next entry //! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу. //! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next() //! \~\sa \a next()
inline bool hasNext() const { inline bool hasNext() const { return pos < (m.size_s() - 1); }
return pos < (m.size_s() - 1);
}
//! \~english Jump to next entry and return true if new position is valid. //! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует. //! \~russian Переходит к следующему элементу и возвращает true если он существует.
@@ -735,9 +886,8 @@ public:
//! \~english Reset iterator to initial position. //! \~english Reset iterator to initial position.
//! \~russian Переходит на начало. //! \~russian Переходит на начало.
//! \~\sa \a next() //! \~\sa \a next()
inline void reset() { inline void reset() { pos = -1; }
pos = -1;
}
private: private:
MapType & m; MapType & m;
ssize_t pos; ssize_t pos;
@@ -776,29 +926,24 @@ private:
template<typename Key, typename T> template<typename Key, typename T>
class PIMapIteratorReverse { class PIMapIteratorReverse {
typedef PIMap<Key, T> MapType; typedef PIMap<Key, T> MapType;
public: public:
PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {} inline PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key. //! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента. //! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value() //! \~\sa \a value()
const Key & key() const { inline const Key & key() const { return m._key(pos); }
return m._key(pos);
}
//! \~english Returns current value. //! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента. //! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key() //! \~\sa \a key()
T & value() { inline T & value() { return m._value(pos); }
return m._value(pos);
}
//! \~english Returns true if iterator can jump to next entry //! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу. //! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next() //! \~\sa \a next()
inline bool hasNext() const { inline bool hasNext() const { return pos > 0; }
return pos > 0;
}
//! \~english Jump to next entry and return true if new position is valid. //! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует. //! \~russian Переходит к следующему элементу и возвращает true если он существует.
@@ -811,9 +956,8 @@ public:
//! \~english Reset iterator to initial position. //! \~english Reset iterator to initial position.
//! \~russian Переходит на начало. //! \~russian Переходит на начало.
//! \~\sa \a next() //! \~\sa \a next()
inline void reset() { inline void reset() { pos = m.size_s(); }
pos = m.size_s();
}
private: private:
MapType & m; MapType & m;
ssize_t pos; ssize_t pos;
@@ -828,8 +972,7 @@ inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v)
s << "{"; s << "{";
bool first = true; bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) { for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) if (!first) s << ", ";
s << ", ";
first = false; first = false;
s << i.key() << ": " << i.value(); s << i.key() << ": " << i.value();
} }
@@ -849,8 +992,7 @@ inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
s << "{"; s << "{";
bool first = true; bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) { for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) if (!first) s << ", ";
s << ", ";
first = false; first = false;
s << i.key() << ": " << i.value(); s << i.key() << ": " << i.value();
} }
@@ -860,7 +1002,9 @@ inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
} }
template<typename Key, typename Type> template<typename Key, typename Type>
inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);} inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {
f.swap(s);
}
#endif // PIMAP_H #endif // PIMAP_H

View File

@@ -44,25 +44,28 @@
//! \~english Class template that provides a way to store two heterogeneous objects as a single unit. //! \~english Class template that provides a way to store two heterogeneous objects as a single unit.
//! \~russian Класс, который позволяет хранить два разнородных объекта как единое целое. //! \~russian Класс, который позволяет хранить два разнородных объекта как единое целое.
//! \~\} //! \~\}
//! \details
//! \~english
//! \~russian
//! \~\sa \a PIMap //! \~\sa \a PIMap
template<typename Type0, typename Type1> template<typename Type0, typename Type1>
class PIPair { class PIPair {
public: public:
//! \~english Constructs an empty PIPair. //! \~english Constructs an empty PIPair.
//! \~russian Создает пустой PIPair. //! \~russian Создает пустой PIPair.
PIPair(): first(), second() {} PIPair(): first(), second() {}
//! \~english Constructs PIPair from [std::tuple](https://en.cppreference.com/w/cpp/utility/tuple). //! \~english Constructs PIPair from [std::tuple](https://en.cppreference.com/w/cpp/utility/tuple).
//! \~russian Создает PIPair из [std::tuple](https://ru.cppreference.com/w/cpp/utility/tuple). //! \~russian Создает PIPair из [std::tuple](https://ru.cppreference.com/w/cpp/utility/tuple).
PIPair(std::tuple<Type0, Type1> tuple) { explicit PIPair(std::tuple<Type0, Type1> tuple) {
first = std::get<0>(tuple); first = std::get<0>(tuple);
second = std::get<1>(tuple); second = std::get<1>(tuple);
} }
//! \~english Constructs PIPair from [std::pair](https://en.cppreference.com/w/cpp/utility/pair).
//! \~russian Создает PIPair из [std::pair](https://ru.cppreference.com/w/cpp/utility/pair).
explicit PIPair(std::pair<Type0, Type1> pair) {
first = pair.first;
second = pair.second;
}
//! \~english Constructs PIPair from values `value0` and `value1`. //! \~english Constructs PIPair from values `value0` and `value1`.
//! \~russian Создает PIPair из `value0` и `value1`. //! \~russian Создает PIPair из `value0` и `value1`.
PIPair(const Type0 & value0, const Type1 & value1) { PIPair(const Type0 & value0, const Type1 & value1) {
@@ -121,24 +124,11 @@ inline PICout operator <<(PICout s, const PIPair<Type0, Type1> & v) {
} }
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
//! \~russian Создает \a PIPair выводя типы из аргументов.
//! \~\details
//! \~\code
//! auto p = createPIPair(1, 'a');
//! piCout << p; // (1, a)
//! \endcode
template< class T1, class T2 >
PIPair<T1,T2> createPIPair(const T1 & f, const T2 & s) {
return PIPair<T1,T2>(f, s);
}
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments. //! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
//! \~russian Создает \a PIPair выводя типы из аргументов. //! \~russian Создает \a PIPair выводя типы из аргументов.
//! \sa \a createPIPair() //! \sa \a createPIPair()
template<class T1, class T2> template<class T1, class T2>
PIPair<T1,T2> createPIPair(T1 && f, T2 && s) { PIPair<T1, T2> createPIPair(T1 f, T2 s) {
return PIPair<T1, T2>(std::move(f), std::move(s)); return PIPair<T1, T2>(std::move(f), std::move(s));
} }

View File

@@ -1,8 +1,17 @@
/*! \file piqueue.h //! \addtogroup Containers
* \brief Queue container //! \{
* //! \file piqueue.h
* This file declare PIQueue //! \brief
*/ //! \~english Declares \a PIQueue
//! \~russian Объявление \a PIQueue
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Queue container Queue container
@@ -28,24 +37,82 @@
#include "pideque.h" #include "pideque.h"
#include "pivector.h" #include "pivector.h"
//! \addtogroup Containers
//! \{
//! \class PIQueue
//! \brief
//! \~english A container class inherited from the \a PIDeque with queue functionality.
//! \~russian Класс контейнера наследованый от \a PIDeque с функциональностью очереди.
//! \~\}
//! \details
//! \~english The container is a array of elements organized according to the FIFO principle (first in, first out).
//! Adds \a enqueue() and \dequeue() functions to \a PIDeque.
//! \~russian Контейнер представляющий массив элементов, организованных по принципу FIFO (первым пришёл — первым вышел).
//! Добавляет к \a PIDeque функции \a enqueue() и \a dequeue().
//! \~\sa \a PIDeque
template<typename T> template<typename T>
class PIQueue: public PIDeque<T> { class PIQueue: public PIDeque<T> {
public: public:
//! \~english Constructs an empty array.
//! \~russian Создает пустой массив.
PIQueue() {} PIQueue() {}
virtual ~PIQueue() {}
PIDeque<T> & enqueue(const T & v) {PIDeque<T>::push_front(v); return *this;} //! \~english Puts an element on the queue.
PIDeque<T> & enqueue(T && v) {PIDeque<T>::push_front(std::move(v)); return *this;} //! \~russian Кладёт элемент в очередь.
PIDeque<T> & enqueue(const T & v) {
PIDeque<T>::push_front(v);
return *this;
}
//! \~english Move an element on the queue.
//! \~russian Перемещает элемент в очередь.
PIDeque<T> & enqueue(T && v) {
PIDeque<T>::push_front(std::move(v));
return *this;
}
//! \~english Retrieves and returns an element from the queue.
//! \~russian Забирает и возвращает элемент из очереди.
//! \~\details
//! \note
//! \~english This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
T dequeue() { return PIDeque<T>::take_back(); } T dequeue() { return PIDeque<T>::take_back(); }
//! \~english Head element of the queue.
//! \~russian Головной (верхний) элемент очереди.
//! \~\details
//! \note
//! \~english Returns a reference to the head element of the queue.
//! This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Возвращает ссылку на головной (верхний) элемент очереди.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
T & head() { return PIDeque<T>::back(); } T & head() { return PIDeque<T>::back(); }
const T & head() const { return PIDeque<T>::back(); } const T & head() const { return PIDeque<T>::back(); }
PIVector<T> toVector() {
PIVector<T> v; //! \~english Tail element of the queue.
v.reserve(PIDeque<T>::size()); //! \~russian Хвостовой (нижний) элемент очереди.
for (uint i = 0; i < PIDeque<T>::size(); ++i) //! \~\details
v.push_back(PIDeque<T>::at(i)); //! \~english Returns a reference to the tail element of the queue.
return v; //! This function assumes that the array isn't empty.
} //! Otherwise will be undefined behavior.
//! \~russian Возвращает ссылку на хвостовой (нижний) элемент очереди.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
T & tail() { return PIDeque<T>::front(); }
const T & tail() const { return PIDeque<T>::front(); }
//! \~english Converts \a PIQueue to \a PIVector.
//! \~russian Преобразует \a PIQueue в \a PIVector.
PIVector<T> toVector() const { return PIVector<T>(PIDeque<T>::data(), PIDeque<T>::size()); }
//! \~english Converts \a PIQueue to \a PIDeque.
//! \~russian Преобразует \a PIQueue в \a PIDeque.
PIDeque<T> toDeque() const { return PIDeque<T>(*this); }
}; };
#endif // PIQUEUE_H #endif // PIQUEUE_H

View File

@@ -37,27 +37,125 @@
template<typename T> template<typename T>
class PISet: public PIMap<T, uchar> { class PISet: public PIMap<T, uchar> {
typedef PIMap<T, uchar> _CSet; typedef PIMap<T, uchar> _CSet;
public: template<typename P, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PISet<T1> & v);
template<typename P, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PISet<T1> & v);
public:
//! Contructs an empty set //! Contructs an empty set
PISet() {} PISet() {}
virtual ~PISet() {;}
//! Contructs set with one element "value" //! Contructs set with one element "value"
PISet(const T & value) {_CSet::insert(value, 0);} explicit PISet(const T & value) { _CSet::insert(value, 0); }
//! Contructs set with elements "v0" and "v1" //! Contructs set with elements "v0" and "v1"
PISet(const T & v0, const T & v1) {_CSet::insert(v0, 0); _CSet::insert(v1, 0);} PISet(const T & v0, const T & v1) {
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
}
//! Contructs set with elements "v0", "v1" and "v2" //! Contructs set with elements "v0", "v1" and "v2"
PISet(const T & v0, const T & v1, const T & v2) {_CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0);} PISet(const T & v0, const T & v1, const T & v2) {
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
_CSet::insert(v2, 0);
}
//! Contructs set with elements "v0", "v1", "v2" and "v3" //! Contructs set with elements "v0", "v1", "v2" and "v3"
PISet(const T & v0, const T & v1, const T & v2, const T & v3) {_CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0); _CSet::insert(v3, 0);} PISet(const T & v0, const T & v1, const T & v2, const T & v3) {
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
_CSet::insert(v2, 0);
_CSet::insert(v3, 0);
}
class const_iterator {
friend class PISet<T>;
private:
inline const_iterator(const PISet<T> * v, ssize_t p): parent(v), pos(p) {}
const PISet<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_iterator(): parent(0), pos(0) {}
inline const T & operator*() const { return parent->pim_index[pos].key; }
inline const T & operator->() const { return parent->pim_index[pos].key; }
inline const_iterator & operator++() {
++pos;
return *this;
}
inline const_iterator operator++(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline const_iterator & operator--() {
--pos;
return *this;
}
inline const_iterator operator--(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline const_iterator & operator+=(const const_iterator & it) {
pos += it.pos;
return *this;
}
inline const_iterator & operator+=(size_t p) {
pos += p;
return *this;
}
inline const_iterator & operator-=(const const_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_iterator & operator-=(size_t p) {
pos -= p;
return *this;
}
friend inline const_iterator operator-(size_t p, const const_iterator & it) { return it - p; }
friend inline const_iterator operator-(const const_iterator & it, size_t p) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const const_iterator & it1, const const_iterator & it2) { return it1.pos - it2.pos; }
friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; }
friend inline const_iterator operator+(const const_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const const_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; }
};
inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, _CSet::size()); }
//! Contructs set from vector of elements //! Contructs set from vector of elements
PISet(const PIVector<T> & values) { explicit PISet(const PIVector<T> & values) {
if (values.isEmpty()) return; if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) { for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0); _CSet::insert(values[i], 0);
@@ -65,7 +163,7 @@ public:
} }
//! Contructs set from deque of elements //! Contructs set from deque of elements
PISet(const PIDeque<T> & values) { explicit PISet(const PIDeque<T> & values) {
if (values.isEmpty()) return; if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) { for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0); _CSet::insert(values[i], 0);
@@ -74,37 +172,49 @@ public:
typedef T key_type; typedef T key_type;
PISet<T> & operator <<(const T & t) {_CSet::insert(t, 0); return *this;} PISet<T> & operator<<(const T & t) {
PISet<T> & operator <<(T && t) {_CSet::insert(std::move(t), 0); return *this;} _CSet::insert(t, 0);
PISet<T> & operator <<(const PISet<T> & other) {(*(_CSet*)this) << *((_CSet*)&other); return *this;} return *this;
}
PISet<T> & operator<<(T && t) {
_CSet::insert(std::move(t), 0);
return *this;
}
PISet<T> & operator<<(const PISet<T> & other) {
(*(_CSet *)this) << *((_CSet *)&other);
return *this;
}
//! \~english Tests if element `key` exists in the set.
//! \~russian Проверяет наличие элемента `key` в массиве.
inline bool contains(const T & t) const { return _CSet::contains(t); }
//! Returns if element "t" exists in this set //! Returns if element "t" exists in this set
bool operator[](const T & t) const { return _CSet::contains(t); } bool operator[](const T & t) const { return _CSet::contains(t); }
//! Returns if element "t" exists in this set //! Returns if element "t" exists in this set
PISet<T> & remove(const T & t) {_CSet::remove(t); return *this;} PISet<T> & remove(const T & t) {
_CSet::remove(t);
return *this;
}
//! Unite set with "v" //! Unite set with "v"
PISet<T> & unite(const PISet<T> & v) { PISet<T> & unite(const PISet<T> & v) {
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) for (const auto & i: v)
_CSet::insert(i.key(), 0); _CSet::insert(i, 0);
return *this; return *this;
} }
//! Subtract set with "v" //! Subtract set with "v"
PISet<T> & subtract(const PISet<T> & v) { PISet<T> & subtract(const PISet<T> & v) {
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) for (const auto & i: v)
_CSet::remove(i.key()); _CSet::remove(i);
return *this; return *this;
} }
//! Intersect set with "v" //! Intersect set with "v"
PISet<T> & intersect(const PISet<T> & v) { PISet<T> & intersect(const PISet<T> & v) {
for (typename _CSet::iterator i = _CSet::begin(); i != _CSet::end(); ++i) _CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); });
if (!v.contains(i.key())) {
_CSet::remove(i.key());
--i;
}
return *this; return *this;
} }
@@ -121,25 +231,54 @@ public:
PISet<T> & operator&=(const PISet<T> & v) { return intersect(v); } PISet<T> & operator&=(const PISet<T> & v) { return intersect(v); }
//! Returns content of set as PIVector //! Returns content of set as PIVector
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << i.key(); return ret;} PIVector<T> toVector() const {
PIVector<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
//! Returns content of set as PIDeque //! Returns content of set as PIDeque
PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << i.key(); return ret;} PIDeque<T> toDeque() const {
PIDeque<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
}; };
//! \relatesalso PISet \brief Returns unite of two sets //! \relatesalso PISet \brief Returns unite of two sets
template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;} template<typename T>
PISet<T> operator+(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
//! \relatesalso PISet \brief Returns subtraction of two sets //! \relatesalso PISet \brief Returns subtraction of two sets
template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;} template<typename T>
PISet<T> operator-(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.subtract(v1);
return ret;
}
//! \relatesalso PISet \brief Returns unite of two sets //! \relatesalso PISet \brief Returns unite of two sets
template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;} template<typename T>
PISet<T> operator|(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
//! \relatesalso PISet \brief Returns intersetion of two sets //! \relatesalso PISet \brief Returns intersetion of two sets
template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;} template<typename T>
PISet<T> operator&(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.intersect(v1);
return ret;
}
template<typename Type> template<typename Type>
@@ -148,11 +287,10 @@ inline PICout operator <<(PICout s, const PISet<Type> & v) {
s.saveAndSetControls(0); s.saveAndSetControls(0);
s << "{"; s << "{";
bool first = true; bool first = true;
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) { for (const auto & i: v) {
if (!first) if (!first) s << ", ";
s << ", ";
first = false; first = false;
s << i.key(); s << i;
} }
s << "}"; s << "}";
s.restoreControls(); s.restoreControls();

View File

@@ -1,8 +1,17 @@
/*! \file pistack.h //! \addtogroup Containers
* \brief Stack container //! \{
* //! \file pistack.h
* This file declare PIStack //! \brief
*/ //! \~english Declares \a PIStack
//! \~russian Объявление \a PIStack
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Stack container Stack container
@@ -25,19 +34,73 @@
#ifndef PISTACK_H #ifndef PISTACK_H
#define PISTACK_H #define PISTACK_H
#include "pideque.h"
#include "pivector.h" #include "pivector.h"
//! \addtogroup Containers
//! \{
//! \class PIStack
//! \brief
//! \~english A container class inherited from the \a PIVector with stack functionality.
//! \~russian Класс контейнера наследованый от \a PIVector с функциональностью стека.
//! \~\}
//! \details
//! \~english The container is a array of elements organized according to the LIFO principle (last in, first out).
//! Adds \a push() and \pop() functions to \a PIVector.
//! \~russian Контейнер представляющий массив элементов, организованных по принципу LIFO (последним пришёл — первым вышел).
//! Добавляет к \a PIVector функции \a push() и \a pop().
//! \~\sa \a PIVector
template<typename T> template<typename T>
class PIStack: public PIVector<T> { class PIStack: public PIVector<T> {
public: public:
PIStack() {;} //! \~english Constructs an empty array.
virtual ~PIStack() {;} //! \~russian Создает пустой массив.
PIVector<T> & push(const T & v) {PIVector<T>::push_back(v); return *this;} PIStack() {}
PIVector<T> & push(T && v) {PIVector<T>::push_back(std::move(v)); return *this;}
//! \~english Puts an element on the stack.
//! \~russian Кладёт элемент в стек.
PIVector<T> & push(const T & v) {
PIVector<T>::push_back(v);
return *this;
}
//! \~english Move an element on the stack.
//! \~russian Перемещает элемент в стек.
PIVector<T> & push(T && v) {
PIVector<T>::push_back(std::move(v));
return *this;
}
//! \~english Retrieves and returns an element from the stack.
//! \~russian Забирает и возвращает элемент из стека.
//! \~\details
//! \note
//! \~english This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
T pop() { return PIVector<T>::take_back(); } T pop() { return PIVector<T>::take_back(); }
//! \~english Top element of the stack
//! \~russian Верхний элемент стека.
//! \~\details
//! \note
//! \~english Returns a reference to the top element of the stack.
//! This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Возвращает ссылку на верхний элемент стека.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
T & top() { return PIVector<T>::back(); } T & top() { return PIVector<T>::back(); }
const T & top() const { return PIVector<T>::back(); } const T & top() const { return PIVector<T>::back(); }
PIVector<T> toVector() {return PIVector<T>(*this);}
//! \~english Converts \a PIStack to \a PIVector.
//! \~russian Преобразует \a PIStack в \a PIVector.
PIVector<T> toVector() const { return PIVector<T>(*this); }
//! \~english Converts \a PIStack to \a PIDeque.
//! \~russian Преобразует \a PIStack в \a PIDeque.
PIDeque<T> toDeque() const { return PIDeque<T>(PIVector<T>::data(), PIVector<T>::size()); }
}; };
#endif // PISTACK_H #endif // PISTACK_H

View File

@@ -74,9 +74,9 @@
//! if the number of elements is known beforehand. //! if the number of elements is known beforehand.
//! //!
//! The complexity (efficiency) of common operations on PIVector is as follows: //! The complexity (efficiency) of common operations on PIVector is as follows:
//! - Random access - constant 𝓞(1) //! - Random access - constant O(1)
//! - Insertion or removal of elements at the end - amortized constant 𝓞(1) //! - Insertion or removal of elements at the end - amortized constant O(1)
//! - Insertion or removal of elements - linear in the distance to the end of the array 𝓞(n) //! - Insertion or removal of elements - linear in the distance to the end of the array O(n)
//! //!
//! \~russian //! \~russian
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы, //! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
@@ -109,9 +109,9 @@
//! если количество элементов известно заранее. //! если количество элементов известно заранее.
//! //!
//! Сложность (эффективность) обычных операций над PIVector следующая: //! Сложность (эффективность) обычных операций над PIVector следующая:
//! - Произвольный доступ — постоянная 𝓞(1) //! - Произвольный доступ — постоянная O(1)
//! - Вставка и удаление элементов в конце — амортизированная постоянная 𝓞(1) //! - Вставка и удаление элементов в конце — амортизированная постоянная O(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n) //! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n)
//! //!
//! \~\sa \a PIDeque, \a PIMap //! \~\sa \a PIDeque, \a PIMap
template<typename T> template<typename T>
@@ -127,15 +127,13 @@ public:
//! \~english Constructs an empty array. //! \~english Constructs an empty array.
//! \~russian Создает пустой массив. //! \~russian Создает пустой массив.
inline PIVector(): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector() { PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) }
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
//! \~english Contructs array from raw `data`. //! \~english Contructs array from raw `data`.
//! This constructor reserve `size` and copy from `data` pointer. //! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`. //! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`. //! То есть выделяет память для `size` элементов и копирует данные из указателя `data`.
inline PIVector(const T * data, size_t size): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector(const T * data, size_t size) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(size); alloc(size);
newT(piv_data, data, piv_size); newT(piv_data, data, piv_size);
@@ -143,7 +141,7 @@ public:
//! \~english Copy constructor. //! \~english Copy constructor.
//! \~russian Копирующий конструктор. //! \~russian Копирующий конструктор.
inline PIVector(const PIVector<T> & v): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector(const PIVector<T> & v) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(v.piv_size); alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size); newT(piv_data, v.piv_data, piv_size);
@@ -158,7 +156,7 @@ public:
//! PIVector <int> v{1,2,3}; //! PIVector <int> v{1,2,3};
//! piCout << v; // {1, 2, 3} //! piCout << v; // {1, 2, 3}
//! \endcode //! \endcode
inline PIVector(std::initializer_list<T> init_list): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector(std::initializer_list<T> init_list) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(init_list.size()); alloc(init_list.size());
newT(piv_data, init_list.begin(), init_list.size()); newT(piv_data, init_list.begin(), init_list.size());
@@ -166,9 +164,9 @@ public:
//! \~english Contructs array with size `size` filled elements `e`. //! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `e`. //! \~russian Создает массив из `size` элементов заполненных `e`.
inline PIVector(size_t size, const T & e = T()): piv_data(0), piv_size(0), piv_rsize(0) { inline explicit PIVector(size_t size, const T & e = T()) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(size, e); expand(size, e);
} }
//! \~english Contructs array with size `size` and elements created by function `f(size_t i)`. //! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
@@ -184,24 +182,26 @@ public:
//! PIVector <int> v(5, [](size_t i){return i*2;}); //! PIVector <int> v(5, [](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4, 6, 8} //! piCout << v; // {0, 2, 4, 6, 8}
//! \endcode //! \endcode
inline PIVector(size_t size, std::function<T(size_t i)> f): piv_data(0), piv_size(0), piv_rsize(0) { inline PIVector(size_t size, std::function<T(size_t i)> f) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(size, f); expand(size, f);
} }
//! \~english Move constructor. //! \~english Move constructor.
//! \~russian Перемещающий конструктор. //! \~russian Перемещающий конструктор.
inline PIVector(PIVector<T> && v): piv_data(v.piv_data), piv_size(v.piv_size), piv_rsize(v.piv_rsize) { inline PIVector(PIVector<T> && v) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
piv_data = v.piv_data;
piv_size = v.piv_size;
piv_rsize = v.piv_rsize;
v._reset(); v._reset();
} }
inline virtual ~PIVector() { inline ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize)) PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
deleteT(piv_data, piv_size); deleteT(piv_data, piv_size);
dealloc(); dealloc();
_reset();
} }
//! \~english Assign operator. //! \~english Assign operator.
@@ -209,7 +209,6 @@ public:
inline PIVector<T> & operator=(const PIVector<T> & v) { inline PIVector<T> & operator=(const PIVector<T> & v) {
if (this == &v) return *this; if (this == &v) return *this;
clear(); clear();
deleteT(piv_data, piv_size);
alloc(v.piv_size); alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size); newT(piv_data, v.piv_data, piv_size);
return *this; return *this;
@@ -224,10 +223,12 @@ public:
class iterator { class iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent; PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -247,7 +248,7 @@ public:
return *this; return *this;
} }
inline iterator operator++(int) { inline iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -256,7 +257,7 @@ public:
return *this; return *this;
} }
inline iterator operator--(int) { inline iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -284,9 +285,7 @@ public:
tmp -= p; tmp -= p;
return tmp; return tmp;
} }
friend inline std::ptrdiff_t operator -(const iterator & it1, const iterator & it2) { friend inline std::ptrdiff_t operator-(const iterator & it1, const iterator & it2) { return it1.pos - it2.pos; }
return it1.pos - it2.pos;
}
friend inline iterator operator+(size_t p, const iterator & it) { return it + p; } friend inline iterator operator+(size_t p, const iterator & it) { return it + p; }
friend inline iterator operator+(const iterator & it, size_t p) { friend inline iterator operator+(const iterator & it, size_t p) {
@@ -297,26 +296,20 @@ public:
inline bool operator==(const iterator & it) const { return (pos == it.pos); } inline bool operator==(const iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const iterator & it) const { return (pos != it.pos); } inline bool operator!=(const iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const iterator & it1, const iterator & it2) { friend inline bool operator<(const iterator & it1, const iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const iterator & it1, const iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const iterator & it1, const iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const iterator & it1, const iterator & it2) { friend inline bool operator>=(const iterator & it1, const iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const iterator & it1, const iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const iterator & it1, const iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_iterator { class const_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline const_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline const_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
const PIVector<T> * parent; const PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -334,7 +327,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator++(int) { inline const_iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -343,7 +336,7 @@ public:
return *this; return *this;
} }
inline const_iterator operator--(int) { inline const_iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -371,9 +364,7 @@ public:
tmp -= p; tmp -= p;
return tmp; return tmp;
} }
friend inline std::ptrdiff_t operator -(const const_iterator & it1, const const_iterator & it2) { friend inline std::ptrdiff_t operator-(const const_iterator & it1, const const_iterator & it2) { return it1.pos - it2.pos; }
return it1.pos - it2.pos;
}
friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; } friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; }
friend inline const_iterator operator+(const const_iterator & it, size_t p) { friend inline const_iterator operator+(const const_iterator & it, size_t p) {
@@ -384,26 +375,20 @@ public:
inline bool operator==(const const_iterator & it) const { return (pos == it.pos); } inline bool operator==(const const_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); } inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const const_iterator & it1, const const_iterator & it2) { friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const const_iterator & it1, const const_iterator & it2) { friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const const_iterator & it1, const const_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class reverse_iterator { class reverse_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline reverse_iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline reverse_iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent; PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -423,7 +408,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator++(int) { inline reverse_iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -432,7 +417,7 @@ public:
return *this; return *this;
} }
inline reverse_iterator operator--(int) { inline reverse_iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -460,9 +445,7 @@ public:
tmp -= p; tmp -= p;
return tmp; return tmp;
} }
friend inline std::ptrdiff_t operator -(const reverse_iterator & it1, const reverse_iterator & it2) { friend inline std::ptrdiff_t operator-(const reverse_iterator & it1, const reverse_iterator & it2) { return it2.pos - it1.pos; }
return it2.pos - it1.pos;
}
friend inline reverse_iterator operator+(size_t p, const reverse_iterator & it) { return it + p; } friend inline reverse_iterator operator+(size_t p, const reverse_iterator & it) { return it + p; }
friend inline reverse_iterator operator+(const reverse_iterator & it, size_t p) { friend inline reverse_iterator operator+(const reverse_iterator & it, size_t p) {
@@ -473,26 +456,20 @@ public:
inline bool operator==(const reverse_iterator & it) const { return (pos == it.pos); } inline bool operator==(const reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); } inline bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const reverse_iterator & it1, const reverse_iterator & it2) { friend inline bool operator<(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const reverse_iterator & it1, const reverse_iterator & it2) { friend inline bool operator>=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
class const_reverse_iterator { class const_reverse_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: private:
inline const_reverse_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {} inline const_reverse_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
const PIVector<T> * parent; const PIVector<T> * parent;
ssize_t pos; ssize_t pos;
public: public:
typedef T value_type; typedef T value_type;
typedef T * pointer; typedef T * pointer;
@@ -509,7 +486,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator++(int) { inline const_reverse_iterator operator++(int) {
auto tmp = *this; const auto tmp = *this;
--*this; --*this;
return tmp; return tmp;
} }
@@ -518,7 +495,7 @@ public:
return *this; return *this;
} }
inline const_reverse_iterator operator--(int) { inline const_reverse_iterator operator--(int) {
auto tmp = *this; const auto tmp = *this;
++*this; ++*this;
return tmp; return tmp;
} }
@@ -559,18 +536,10 @@ public:
inline bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); } inline bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); } inline bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator <(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { friend inline bool operator<(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos < it2.pos; }
return it1.pos < it2.pos; friend inline bool operator<=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos <= it2.pos; }
} friend inline bool operator>(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator <=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { friend inline bool operator>=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos >= it2.pos; }
return it1.pos <= it2.pos;
}
friend inline bool operator >(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
}; };
//! \~english Iterator to the first element. //! \~english Iterator to the first element.
@@ -748,6 +717,35 @@ public:
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти. //! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline const T & at(size_t index) const { return piv_data[index]; } inline const T & at(size_t index) const { return piv_data[index]; }
//! \~english Returns the first element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает первый элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a indexWhere()
inline const T & atWhere(std::function<bool(const T & e)> test, ssize_t start = 0, const T & def = T()) const {
const ssize_t i = indexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Returns the last element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает последний элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a lastIndexWhere()
inline const T & lastAtWhere(std::function<bool(const T & e)> test, ssize_t start = -1, const T & def = T()) const {
const ssize_t i = lastIndexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Last element. //! \~english Last element.
//! \~russian Последний элемент массива. //! \~russian Последний элемент массива.
//! \~\details //! \~\details
@@ -802,7 +800,7 @@ public:
//! возвращается **false**, что означает, что массив даже не просматривается. //! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<int> v{1, 2, 3, 4}; //! PIVector<int> v{1, 2, 3, 4};
@@ -829,6 +827,33 @@ public:
return false; return false;
} }
//! \~english Tests if all elements of `v` exists in the array.
//! \~russian Проверяет наличие всех элементов `v` в массиве.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 3, 4};
//! piCout << v.contains({1,4}); // true
//! piCout << v.contains({1,5}); // false
//! \endcode
//! \~\sa \a every(), \a any(), \a entries(), \a forEach()
inline bool contains(const PIVector<T> & v, ssize_t start = 0) const {
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (const T & e: v) {
bool c = false;
for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) {
c = true;
break;
}
}
if (!c) return false;
}
return true;
}
//! \~english Count elements equal `e` in the array. //! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве. //! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details //! \~\details
@@ -845,7 +870,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<int> v{2, 2, 4, 2, 6}; //! PIVector<int> v{2, 2, 4, 2, 6};
@@ -885,7 +910,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается. //! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexWhere() //! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexWhere()
inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const { inline int entries(std::function<bool(const T & e)> test, ssize_t start = 0) const {
@@ -918,7 +943,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<int> v{2, 5, 9}; //! PIVector<int> v{2, 5, 9};
@@ -959,7 +984,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается. //! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив. //! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив. //! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code //! \~\code
//! PIVector<PIString> v{"do", "re", "mi", "re"}; //! PIVector<PIString> v{"do", "re", "mi", "re"};
@@ -999,7 +1024,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1042,7 +1067,7 @@ public:
//! c которого начинать поиск в обратном направлении. //! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив. //! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива. //! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу. //! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается. //! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента //! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив. //! и означает, что просматривается весь массив.
@@ -1109,7 +1134,7 @@ public:
PIVector<T> getRange(size_t index, size_t count) const { PIVector<T> getRange(size_t index, size_t count) const {
if (index >= piv_size || count == 0) return PIVector<T>(); if (index >= piv_size || count == 0) return PIVector<T>();
if (index + count > piv_size) count = piv_size - index; if (index + count > piv_size) count = piv_size - index;
return PIVector(&(piv_data[index]), count); return PIVector(piv_data + index, count);
} }
//! \~english Clear array, remove all elements. //! \~english Clear array, remove all elements.
@@ -1119,16 +1144,13 @@ public:
//! \~english Reserved memory will not be released. //! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится. //! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize() //! \~\sa \a resize()
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & clear() { inline PIVector<T> & clear() {
resize(0); deleteT(piv_data, piv_size);
piv_size = 0;
return *this; return *this;
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & clear() { inline PIVector<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size) PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size)
piv_size = 0; piv_size = 0;
@@ -1179,16 +1201,12 @@ public:
//! \~english First does `resize(new_size)` then `fill(e)`. //! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`. //! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize() //! \~\sa \a fill(), \a resize()
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & assign(size_t new_size, const T & f) { inline PIVector<T> & assign(size_t new_size, const T & f) {
resize(new_size); resize(new_size);
return fill(f); return fill(f);
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & assign(size_t new_size, const T & f) { inline PIVector<T> & assign(size_t new_size, const T & f) {
_resizeRaw(new_size); _resizeRaw(new_size);
return fill(f); return fill(f);
@@ -1207,17 +1225,10 @@ public:
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIVector<T> & resize(size_t new_size, const T & e = T()) { inline PIVector<T> & resize(size_t new_size, const T & e = T()) {
if (new_size < piv_size) { if (new_size < piv_size) {
T * de = &(piv_data[new_size]); deleteT(piv_data + new_size, piv_size - new_size);
deleteT(de, piv_size - new_size);
piv_size = new_size; piv_size = new_size;
} } else if (new_size > piv_size) {
if (new_size > piv_size) { expand(new_size, e);
size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, e);
}
} }
return *this; return *this;
} }
@@ -1235,38 +1246,29 @@ public:
//! \~\sa \a size(), \a clear() //! \~\sa \a size(), \a clear()
inline PIVector<T> & resize(size_t new_size, std::function<T(size_t i)> f) { inline PIVector<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size < piv_size) { if (new_size < piv_size) {
T * de = &(piv_data[new_size]); deleteT(piv_data + new_size, piv_size - new_size);
deleteT(de, piv_size - new_size);
piv_size = new_size; piv_size = new_size;
} } else if (new_size > piv_size) {
if (new_size > piv_size) { expand(new_size, f);
size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f(i));
}
} }
return *this; return *this;
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & _resizeRaw(size_t new_size) { inline PIVector<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
if (new_size > piv_size) { if (new_size > piv_size) {
PIINTROSPECTION_CONTAINER_USED(T, (new_size - piv_size)); PIINTROSPECTION_CONTAINER_USED(T, (new_size - piv_size));
} }
if (new_size < piv_size) { if (new_size < piv_size) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size - new_size)); PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size - new_size));
} }
#endif
alloc(new_size); alloc(new_size);
return *this; return *this;
} }
inline void _copyRaw(T * dst, const T * src, size_t size) { inline void _copyRaw(T * dst, const T * src, size_t size) { newT(dst, src, size); }
newT(dst, src, size);
}
//! \~english Attempts to allocate memory for at least `new_size` elements. //! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов. //! \~russian Резервируется память под как минимум `new_size` элементов.
@@ -1284,7 +1286,7 @@ public:
//! \~\sa \a size(), \a capacity(), \a resize() //! \~\sa \a size(), \a capacity(), \a resize()
inline PIVector<T> & reserve(size_t new_size) { inline PIVector<T> & reserve(size_t new_size) {
if (new_size <= piv_rsize) return *this; if (new_size <= piv_rsize) return *this;
size_t os = piv_size; const size_t os = piv_size;
alloc(new_size); alloc(new_size);
piv_size = os; piv_size = os;
return *this; return *this;
@@ -1304,8 +1306,8 @@ public:
inline PIVector<T> & insert(size_t index, const T & e = T()) { inline PIVector<T> & insert(size_t index, const T & e = T()) {
alloc(piv_size + 1); alloc(piv_size + 1);
if (index < piv_size - 1) { if (index < piv_size - 1) {
size_t os = piv_size - index - 1; const size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
} }
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, e); elementNew(piv_data + index, e);
@@ -1321,8 +1323,8 @@ public:
inline PIVector<T> & insert(size_t index, T && e) { inline PIVector<T> & insert(size_t index, T && e) {
alloc(piv_size + 1); alloc(piv_size + 1);
if (index < piv_size - 1) { if (index < piv_size - 1) {
size_t os = piv_size - index - 1; const size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
} }
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, std::move(e)); elementNew(piv_data + index, std::move(e));
@@ -1339,14 +1341,16 @@ public:
if (v.isEmpty()) return *this; if (v.isEmpty()) return *this;
#ifndef NDEBUG #ifndef NDEBUG
if (&v == this) { if (&v == this) {
printf("error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(&v != this); assert(&v != this);
ssize_t os = piv_size - index; const ssize_t os = piv_size - index;
alloc(piv_size + v.piv_size); alloc(piv_size + v.piv_size);
if (os > 0) { if (os > 0) {
memmove((void*)(&(piv_data[index + v.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove(reinterpret_cast<void *>(piv_data + index + v.piv_size),
reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T));
} }
newT(piv_data + index, v.piv_data, v.piv_size); newT(piv_data + index, v.piv_data, v.piv_size);
return *this; return *this;
@@ -1363,10 +1367,13 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove() //! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, std::initializer_list<T> init_list) { inline PIVector<T> & insert(size_t index, std::initializer_list<T> init_list) {
ssize_t os = piv_size - index; if (init_list.size() == 0) return *this;
const ssize_t os = piv_size - index;
alloc(piv_size + init_list.size()); alloc(piv_size + init_list.size());
if (os > 0) { if (os > 0) {
memmove((void*)(&(piv_data[index + init_list.size()])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove(reinterpret_cast<void *>(piv_data + index + init_list.size()),
reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T));
} }
newT(piv_data + index, init_list.begin(), init_list.size()); newT(piv_data + index, init_list.begin(), init_list.size());
return *this; return *this;
@@ -1384,13 +1391,16 @@ public:
inline PIVector<T> & remove(size_t index, size_t count = 1) { inline PIVector<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this; if (count == 0) return *this;
if (index + count >= piv_size) { if (index + count >= piv_size) {
resize(index); if (index < piv_size) {
return *this; deleteT(piv_data + index, piv_size - index);
piv_size = index;
} }
size_t os = piv_size - index - count; } else {
deleteT(&(piv_data[index]), count); const size_t os = piv_size - index - count;
memmove((void*)(&(piv_data[index])), (const void*)(&(piv_data[index + count])), os * sizeof(T)); deleteT(piv_data + index, count);
memmove(reinterpret_cast<void *>(piv_data + index), reinterpret_cast<const void *>(piv_data + index + count), os * sizeof(T));
piv_size -= count; piv_size -= count;
}
return *this; return *this;
} }
@@ -1410,11 +1420,11 @@ public:
//! \~\details //! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved. //! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using operator<. //! Elements are compared using operator<.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort). //! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`. //! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется. //! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется оператор `operator<`. //! Для сравнения элементов используется оператор `operator<`.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). //! Для сортировки используется функция [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort).
//! Сложность сортировки `O(N·log(N))`. //! Сложность сортировки `O(N·log(N))`.
//! \~\code //! \~\code
//! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3}; //! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
@@ -1423,7 +1433,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp) //! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp)
inline PIVector<T> & sort() { inline PIVector<T> & sort() {
std::sort(begin(), end()); std::stable_sort(begin(), end());
return *this; return *this;
} }
@@ -1440,20 +1450,15 @@ public:
//! While the signature does not need to have const &, the function must not modify the objects passed to it. //! While the signature does not need to have const &, the function must not modify the objects passed to it.
//! The function must return `false` for identical elements, //! The function must return `false` for identical elements,
//! otherwise, it will lead to undefined program behavior and memory errors. //! otherwise, it will lead to undefined program behavior and memory errors.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort). //! Sorting provided by [std::stable_sort](https://en.cppreference.com/w/cpp/algorithm/stable_sort).
//! Complexity `O(N·log(N))`. //! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется. //! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`. //! Для сравнения элементов используется функция сравнения `comp`.
//! Функция сравнения, возвращает `true` если первый аргумент меньше второго. //! Функция сравнения, возвращает `true` если первый аргумент меньше
//! Сигнатура функции сравнения должна быть эквивалентна следующей: //! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура
//! \code //! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для
//! bool comp(const T &a, const T &b); //! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция
//! \endcode //! [std::stable_sort](https://ru.cppreference.com/w/cpp/algorithm/stable_sort). Сложность сортировки `O(N·log(N))`.
//! Сигнатура не обязана содержать const &, однако, функция не может изменять переданные объекты.
//! Функция обязана возвращать `false` для одинаковых элементов,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code //! \~\code
//! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3}; //! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;}); //! v.sort([](const int & a, const int & b){return a > b;});
@@ -1461,7 +1466,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a sort() //! \~\sa \a sort()
inline PIVector<T> & sort(std::function<bool(const T & a, const T & b)> comp) { inline PIVector<T> & sort(std::function<bool(const T & a, const T & b)> comp) {
std::sort(begin(), end(), comp); std::stable_sort(begin(), end(), comp);
return *this; return *this;
} }
@@ -1482,7 +1487,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a reversed() //! \~\sa \a reversed()
inline PIVector<T> & reverse() { inline PIVector<T> & reverse() {
size_t s2 = piv_size/2; const size_t s2 = piv_size / 2;
for (size_t i = 0; i < s2; ++i) { for (size_t i = 0; i < s2; ++i) {
piSwap<T>(piv_data[i], piv_data[piv_size - i - 1]); piSwap<T>(piv_data[i], piv_data[piv_size - i - 1]);
} }
@@ -1513,9 +1518,11 @@ public:
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым. //! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize() //! \~\sa \a resize()
inline PIVector<T> & enlarge(ssize_t add_size, const T & e = T()) { inline PIVector<T> & enlarge(ssize_t add_size, const T & e = T()) {
ssize_t ns = size_s() + add_size; const ssize_t ns = size_s() + add_size;
if (ns <= 0) clear(); if (ns <= 0)
else resize(size_t(ns), e); clear();
else
resize(size_t(ns), e);
return *this; return *this;
} }
@@ -1548,12 +1555,15 @@ public:
//! \endcode //! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere() //! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIVector<T> & removeAll(const T & e) { inline PIVector<T> & removeAll(const T & e) {
for (ssize_t i = 0; i < size_s(); ++i) { ssize_t j = indexOf(e);
if (piv_data[i] == e) { if (j != -1) {
remove(i); for (size_t i = j + 1; i < piv_size; ++i) {
--i; if (piv_data[i] != e) {
piv_data[j++] = std::move(piv_data[i]);
} }
} }
remove(j, piv_size - j);
}
return *this; return *this;
} }
@@ -1569,12 +1579,15 @@ public:
//! \endcode //! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere() //! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIVector<T> & removeWhere(std::function<bool(const T & e)> test) { inline PIVector<T> & removeWhere(std::function<bool(const T & e)> test) {
for (ssize_t i = 0; i < size_s(); ++i) { ssize_t j = indexWhere(test);
if (test(piv_data[i])) { if (j != -1) {
remove(i); for (size_t i = j + 1; i < piv_size; ++i) {
--i; if (!test(piv_data[i])) {
piv_data[j++] = std::move(piv_data[i]);
} }
} }
remove(j, piv_size - j);
}
return *this; return *this;
} }
@@ -1633,7 +1646,8 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIVector<T> & push_back(std::initializer_list<T> init_list) { inline PIVector<T> & push_back(std::initializer_list<T> init_list) {
size_t ps = piv_size; if (init_list.size() == 0) return *this;
const size_t ps = piv_size;
alloc(piv_size + init_list.size()); alloc(piv_size + init_list.size());
newT(piv_data + ps, init_list.begin(), init_list.size()); newT(piv_data + ps, init_list.begin(), init_list.size());
return *this; return *this;
@@ -1646,13 +1660,14 @@ public:
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_back() //! \~\sa \a push_back()
inline PIVector<T> & push_back(const PIVector<T> & v) { inline PIVector<T> & push_back(const PIVector<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG #ifndef NDEBUG
if (&v == this) { if (&v == this) {
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(&v != this); assert(&v != this);
size_t ps = piv_size; const size_t ps = piv_size;
alloc(piv_size + v.piv_size); alloc(piv_size + v.piv_size);
newT(piv_data + ps, v.piv_data, v.piv_size); newT(piv_data + ps, v.piv_data, v.piv_size);
return *this; return *this;
@@ -1767,10 +1782,7 @@ public:
//! piCout << v; // {5, 4, 1, 2, 3} //! piCout << v; // {5, 4, 1, 2, 3}
//! \endcode //! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert() //! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIVector<T> & push_front(const T & e) { inline PIVector<T> & push_front(const T & e) { return insert(0, e); }
insert(0, e);
return *this;
}
//! \~english Appends the given element `e` to the begin of the array. //! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива. //! \~russian Добавляет элемент `e` в начало массива.
@@ -1778,10 +1790,7 @@ public:
//! \~english Overloaded function. //! \~english Overloaded function.
//! \~russian Перегруженая функция. //! \~russian Перегруженая функция.
//! \~\sa \a push_front() //! \~\sa \a push_front()
inline PIVector<T> & push_front(T && e) { inline PIVector<T> & push_front(T && e) { return insert(0, std::move(e)); }
insert(0, std::move(e));
return *this;
}
//! \~english Appends the given array `v` to the begin of the array. //! \~english Appends the given array `v` to the begin of the array.
//! \~russian Добавляет массив `v` в начало массива. //! \~russian Добавляет массив `v` в начало массива.
@@ -1794,10 +1803,7 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3} //! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode //! \endcode
//! \~\sa \a push_front() //! \~\sa \a push_front()
inline PIVector<T> & push_front(const PIVector<T> & v) { inline PIVector<T> & push_front(const PIVector<T> & v) { return insert(0, v); }
insert(0, v);
return *this;
}
//! \~english Appends the given elements to the begin of the array. //! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива. //! \~russian Добавляет элементы в начало массива.
@@ -1809,10 +1815,7 @@ public:
//! Добавляет элементы из //! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list). //! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append() //! \~\sa \a append()
inline PIVector<T> & push_front(std::initializer_list<T> init_list) { inline PIVector<T> & push_front(std::initializer_list<T> init_list) { return insert(0, init_list); }
insert(0, init_list);
return *this;
}
//! \~english Appends the given element `e` to the begin of the array. //! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива. //! \~russian Добавляет элемент `e` в начало массива.
@@ -1880,7 +1883,8 @@ public:
//! \~\sa \a pop_front(), \a take_back(), \a take_front() //! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIVector<T> & pop_back() { inline PIVector<T> & pop_back() {
if (piv_size == 0) return *this; if (piv_size == 0) return *this;
resize(piv_size - 1); deleteT(piv_data + piv_size - 1, 1);
piv_size = piv_size - 1;
return *this; return *this;
} }
@@ -1915,7 +1919,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() { inline T take_back() {
T e(back()); const T e(back());
pop_back(); pop_back();
return e; return e;
} }
@@ -1930,7 +1934,7 @@ public:
//! \endcode //! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front() //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() { inline T take_front() {
T e(front()); const T e(front());
pop_front(); pop_front();
return e; return e;
} }
@@ -1946,7 +1950,8 @@ public:
//! \~\sa \a map() //! \~\sa \a map()
template<typename ST> template<typename ST>
inline PIVector<ST> toType() const { inline PIVector<ST> toType() const {
PIVector<ST> ret; ret.reserve(piv_size); PIVector<ST> ret;
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) { for (size_t i = 0; i < piv_size; ++i) {
ret << ST(piv_data[i]); ret << ST(piv_data[i]);
} }
@@ -1954,9 +1959,9 @@ public:
} }
//! \~english Returns a new array with all elements //! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `test`. //! that pass the test implemented by the provided function `bool test(const T & e)`.
//! \~russian Возвращает новый массив со всеми элементами, //! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `test`. //! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`.
//! \~\details //! \~\details
//! \~\code //! \~\code
//! PIVector<int> v{3, 2, 5, 2, 7}; //! PIVector<int> v{3, 2, 5, 2, 7};
@@ -1972,6 +1977,39 @@ public:
return ret; return ret;
} }
//! \~english Same as \a filter() but with `index` parameter in `test`.
//! \~russian Аналогично \a filter() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filter()
inline PIVector<T> filterIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIVector<T> ret;
for (size_t i = 0; i < piv_size; ++i) {
if (test(i, piv_data[i])) ret << piv_data[i];
}
return ret;
}
//! \~english Same as \a filter() but from end to begin (from right to left).
//! \~russian Аналогично \a filter() но от конца до начала (справа на лево).
//! \~\sa \a filter()
inline PIVector<T> filterReverse(std::function<bool(const T & e)> test) const {
PIVector<T> ret;
for (ssize_t i = piv_size; i >= 0; --i) {
if (test(piv_data[i])) ret << piv_data[i];
}
return ret;
}
//! \~english Same as \a filterReverse() but with `index` parameter in `test`.
//! \~russian Аналогично \a filterReverse() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filterReverse()
inline PIVector<T> filterReverseIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIVector<T> ret;
for (ssize_t i = piv_size; i >= 0; --i) {
if (test(i, piv_data[i])) ret << piv_data[i];
}
return ret;
}
//! \~english Execute function `void f(const T & e)` for every element in array. //! \~english Execute function `void f(const T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива. //! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details //! \~\details
@@ -2012,6 +2050,63 @@ public:
return *this; return *this;
} }
//! \~english Same as \a forEach() but with `index` parameter in `f`.
//! \~russian Аналогично \a forEach() но с параметром индекса `index` в функции `f`.
//! \~\sa \a forEach()
inline void forEachIndexed(std::function<void(size_t index, const T & e)> f) const {
for (size_t i = 0; i < piv_size; ++i) {
f(i, piv_data[i]);
}
}
//! \~english Same as \a forEachIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachIndexed()
inline PIVector<T> & forEachIndexed(std::function<void(size_t index, T & e)> f) {
for (size_t i = 0; i < piv_size; ++i) {
f(i, piv_data[i]);
}
return *this;
}
//! \~english Same as \a forEach() but from end to begin (from right to left).
//! \~russian Аналогично \a forEach() но от конца до начала (справа на лево).
//! \~\sa \a forEach()
inline void forEachReverse(std::function<void(const T & e)> f) const {
for (ssize_t i = piv_size; i >= 0; --i) {
f(piv_data[i]);
}
}
//! \~english Same as \a forEachReverse(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverse(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachReverse()
inline PIVector<T> & forEachReverse(std::function<void(T & e)> f) {
for (ssize_t i = piv_size; i >= 0; --i) {
f(piv_data[i]);
}
return *this;
}
//! \~english Same as \a forEachIndexed() but from end to begin (from right to left).
//! \~russian Аналогично \a forEachIndexed() но от конца до начала (справа на лево).
//! \~\sa \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline void forEachReverseIndexed(std::function<void(size_t index, const T & e)> f) const {
for (ssize_t i = piv_size; i >= 0; --i) {
f(i, piv_data[i]);
}
}
//! \~english Same as \a forEachReverseIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverseIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEachReverseIndexed(), \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline PIVector<T> & forEachReverseIndexed(std::function<void(size_t index, T & e)> f) {
for (ssize_t i = piv_size; i >= 0; --i) {
f(i, piv_data[i]);
}
return *this;
}
//! \~english Сreates a new array populated with the results //! \~english Сreates a new array populated with the results
//! of calling a provided function `ST f(const T & e)` on every element in the calling array. //! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции //! \~russian Создаёт новый массив с результатом вызова указанной функции
@@ -2026,18 +2121,73 @@ public:
//! \~\code //! \~\code
//! PIVector<int> v{1, 2, 3}; //! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);}); //! PIVector<PIString> sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; {"1", "2", "3"} //! piCout << sl; // {"1", "2", "3"}
//! \endcode //! \endcode
//! \~\sa \a forEach(), \a reduce() //! \~\sa \a forEach(), \a reduce()
template<typename ST> template<typename ST>
inline PIVector<ST> map(std::function<ST(const T & e)> f) const { inline PIVector<ST> map(std::function<ST(const T & e)> f) const {
PIVector<ST> ret; ret.reserve(piv_size); PIVector<ST> ret;
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) { for (size_t i = 0; i < piv_size; ++i) {
ret << f(piv_data[i]); ret << f(piv_data[i]);
} }
return ret; return ret;
} }
//! \~english Same as \a map() but with `index` parameter in `f`.
//! \~russian Аналогично \a map() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.mapIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"0", "1", "2"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIVector<ST> mapIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) {
ret << f(i, piv_data[i]);
}
return ret;
}
//! \~english Same as \a map() but from end to begin (from right to left).
//! \~russian Аналогично \a map() но от конца до начала (справа на лево).
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.mapReverse<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"3", "2", "1"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIVector<ST> mapReverse(std::function<ST(const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (ssize_t i = piv_size; i >= 0; --i) {
ret << f(piv_data[i]);
}
return ret;
}
//! \~english Same as \a mapReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a mapReverse() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.mapReverseIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"2", "1", "0"}
//! \endcode
//! \~\sa \a mapReverse()
template<typename ST>
inline PIVector<ST> mapReverseIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (ssize_t i = piv_size; i >= 0; --i) {
ret << f(i, piv_data[i]);
}
return ret;
}
//! \~english Applies the function `ST f(const T & e, const ST & acc)` //! \~english Applies the function `ST f(const T & e, const ST & acc)`
//! to each element of the array (from left to right), returns one value. //! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)` //! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
@@ -2088,6 +2238,42 @@ public:
return ret; return ret;
} }
//! \~english Same as \a reduce() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduce() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < piv_size; ++i) {
ret = f(i, piv_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduce() but from end to begin (from right to left).
//! \~russian Аналогично \a reduce() но от конца до начала (справа на лево).
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceReverse(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = piv_size; i >= 0; --i) {
ret = f(piv_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduceReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduceReverse() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduceReverse()
template<typename ST>
inline ST reduceReverseIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = piv_size; i >= 0; --i) {
ret = f(i, piv_data[i], ret);
}
return ret;
}
//! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array. //! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный. //! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details //! \~\details
@@ -2110,13 +2296,13 @@ public:
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const { inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
#ifndef NDEBUG #ifndef NDEBUG
if (rows * cols != piv_size) { if (rows * cols != piv_size) {
printf("error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(rows * cols == piv_size); assert(rows * cols == piv_size);
PIVector<PIVector<T>> ret; PIVector<PIVector<T>> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
ret.resize(rows); ret.expand(rows);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r] = PIVector<T>(&(piv_data[r * cols]), cols); ret[r] = PIVector<T>(&(piv_data[r * cols]), cols);
@@ -2147,14 +2333,12 @@ public:
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6} //! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if< template<typename C, typename std::enable_if<std::is_same<T, PIVector<C>>::value, int>::type = 0>
std::is_same<T, PIVector<C>>::value
, int>::type = 0>
inline PIVector<C> flatten(ReshapeOrder order = ReshapeByRow) const { inline PIVector<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIVector<C> ret; PIVector<C> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
size_t rows = size(); const size_t rows = size();
size_t cols = at(0).size(); const size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == ReshapeByRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
@@ -2190,108 +2374,196 @@ public:
//! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}} //! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}}
//! \endcode //! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape() //! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if< template<typename C, typename std::enable_if<std::is_same<T, PIVector<C>>::value, int>::type = 0>
std::is_same<T, PIVector<C>>::value
, int>::type = 0>
inline PIVector<PIVector<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const { inline PIVector<PIVector<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
PIVector<C> fl = flatten<C>(); PIVector<C> fl = flatten<C>();
return fl.reshape(rows, cols, order); return fl.reshape(rows, cols, order);
} }
//! \~english Divides an array into a two-dimensional array using the separator `separator`.
//! \~russian Разделяет массив на двумерный массив с помощью разделителя`separator`.
//! \~\code
//! PIVector<int> v{1, 2, 3, 99, 4, 5, 99, 6};
//! piCout << v.split(99); // {{1, 2, 3}, {4, 5}, {6}}
//! \endcode
//! \~\sa \a splitBySize()
inline PIVector<PIVector<T>> split(const T & separator) const {
PIVector<PIVector<T>> ret;
if (isEmpty()) return ret;
size_t start = 0;
ssize_t ci = indexOf(separator, start);
while (ci >= 0) {
ret << PIVector<T>(piv_data + start, ci - start);
start = ci + 1;
ci = indexOf(separator, start);
}
if (start < piv_size) {
ret << PIVector<T>(piv_data + start, piv_size - start);
}
return ret;
}
//! \~english Divides an array into a two-dimensional array in chunks of no more than `sz`.
//! \~russian Разделяет массив на двумерный массив по кускам не более чем `sz`.
//! \~\sa \a split()
inline PIVector<PIVector<T>> splitBySize(size_t sz) const {
PIVector<PIVector<T>> ret;
if (isEmpty() || sz == 0) return ret;
const size_t ch = piv_size / sz;
for (size_t i = 0; i < ch; ++i) {
ret << PIVector<T>(piv_data + sz * i, sz);
}
const size_t t = ch * sz;
if (t < piv_size) {
ret << PIVector<T>(piv_data + t, piv_size - t);
}
return ret;
}
//! \~english Cut sub-array of this array.
//! \~russian Вырезает подмассив, то есть кусок из текущего массива.
//! \~english
//! \param index - index of this array where sub-array starts
//! \param count - sub-array size
//! \~russian
//! \param index - индекс в текущем массиве, откуда начинётся подмассив
//! \param count - размер подмассива
//! \~\details
//! \~english
//! Index must be in range from `0` to `size()-1`.
//! If sub-array size more than this array size, than ends early.
//! \~russian
//! Индекс начала должен лежать в диапазоне от `0` до `size()-1`.
//! Если заданный размер подмассива превышает размер текущего массива,
//! то вернется подмассив меньшего размера (`size()-index-1`).
inline PIVector<T> takeRange(size_t index, size_t count) {
PIVector<T> ret;
if (index >= piv_size || count == 0) return ret;
if (index + count > piv_size) count = piv_size - index;
ret.alloc(count);
memcpy(reinterpret_cast<void *>(ret.piv_data), reinterpret_cast<const void *>(piv_data + index), count * sizeof(T));
const size_t os = piv_size - index - count;
if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index), reinterpret_cast<const void *>(piv_data + index + count), os * sizeof(T));
piv_size -= count;
} else {
piv_size = index;
}
return ret;
}
private: private:
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;} inline void _reset() {
inline size_t asize(size_t s) { piv_size = 0;
if (s == 0) return 0; piv_rsize = 0;
if (piv_rsize + piv_rsize >= s && piv_rsize < s) { piv_data = nullptr;
return piv_rsize + piv_rsize;
} }
ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
while (s_ >> t) template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
++t;
return (1 << t);
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s) PIINTROSPECTION_CONTAINER_USED(T, s)
for (size_t i = 0; i < s; ++i) for (size_t i = 0; i < s; ++i) {
elementNew(dst + i, src[i]); elementNew(dst + i, src[i]);
} }
template<typename T1 = T, typename std::enable_if< }
std::is_trivially_copyable<T1>::value
, int>::type = 0> template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) { inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s) PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy((void*)(dst), (const void*)(src), s * sizeof(T)); memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<const void *>(src), s * sizeof(T));
} }
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) { if (d != nullptr) {
for (size_t i = 0; i < sz; ++i) { for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
} }
} }
} }
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
, int>::type = 0>
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
} }
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
, int>::type = 0> inline void elementNew(T * to, const T & from) {
inline void elementNew(T * to, const T & from) {new(to)T(from);} new (to) T(from);
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {new(to)T(std::move(from));}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {(*to) = from;}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {(*to) = std::move(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {from.~T();}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {}
inline void dealloc() {
if ((uchar*)piv_data != 0) free((uchar*)piv_data);
piv_data = 0;
} }
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
new (to) T(std::move(from));
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {
(*to) = from;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
(*to) = std::move(from);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementDelete(T & from) {
from.~T();
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementDelete(T & from) {}
inline void dealloc() {
if (piv_data != nullptr) {
free(reinterpret_cast<void *>(piv_data));
piv_data = nullptr;
}
}
inline void expand(size_t new_size, const T & e = T()) {
const size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, e);
}
}
inline void expand(size_t new_size, std::function<T(size_t i)> f) {
const size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f(i));
}
}
inline void alloc(size_t new_size) { inline void alloc(size_t new_size) {
if (new_size <= piv_rsize) { if (new_size <= piv_rsize) {
piv_size = new_size; piv_size = new_size;
return; return;
} }
piv_size = new_size; piv_size = new_size;
size_t as = asize(new_size); const size_t new_rsize = _PIContainerConstants<T>::calcNewSize(piv_rsize, new_size);
if (as == piv_rsize) return; if (new_rsize == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - piv_rsize)) PIINTROSPECTION_CONTAINER_ALLOC(T, (as - piv_rsize))
T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T))); T * new_data = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), new_rsize * sizeof(T)));
#ifndef NDEBUG #ifndef NDEBUG
if (!p_d) { if (!new_data) {
printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T)); fprintf(stderr, "error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
} }
#endif #endif
assert(p_d); assert(new_data);
piv_data = p_d; piv_data = new_data;
piv_rsize = as; piv_rsize = new_rsize;
} }
T * piv_data; T * piv_data = nullptr;
size_t piv_size, piv_rsize; size_t piv_size = 0;
size_t piv_rsize = 0;
}; };
@@ -2330,6 +2602,8 @@ inline PICout operator <<(PICout s, const PIVector<T> & v) {
} }
template<typename T> template<typename T>
inline void piSwap(PIVector<T> & f, PIVector<T> & s) {f.swap(s);} inline void piSwap(PIVector<T> & f, PIVector<T> & s) {
f.swap(s);
}
#endif // PIVECTOR_H #endif // PIVECTOR_H

View File

@@ -39,17 +39,17 @@ template <typename T>
class PIVector2D { class PIVector2D {
public: public:
inline PIVector2D() { rows_ = cols_ = 0; } inline PIVector2D() { rows_ = cols_ = 0; }
inline PIVector2D(size_t rows, size_t cols, const T & f = T()) { inline PIVector2D(size_t rows, size_t cols, const T & f = T()) {
rows_ = rows; rows_ = rows;
cols_ = cols; cols_ = cols;
mat.resize(rows * cols, f); mat.resize(rows * cols, f);
} }
inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v) : rows_(rows), cols_(cols), mat(v) {
mat.resize(rows*cols); inline PIVector2D(size_t rows, size_t cols, const PIVector<T> & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); }
}
inline PIVector2D(size_t rows, size_t cols, PIVector<T> && v) : rows_(rows), cols_(cols), mat(std::move(v)) { inline PIVector2D(size_t rows, size_t cols, PIVector<T> && v): rows_(rows), cols_(cols), mat(std::move(v)) { mat.resize(rows * cols); }
mat.resize(rows*cols);
}
inline PIVector2D(const PIVector<PIVector<T>> & v) { inline PIVector2D(const PIVector<PIVector<T>> & v) {
rows_ = v.size(); rows_ = v.size();
if (rows_) { if (rows_) {
@@ -64,19 +64,32 @@ public:
} }
inline size_t rows() const { return rows_; } inline size_t rows() const { return rows_; }
inline size_t cols() const { return cols_; } inline size_t cols() const { return cols_; }
inline size_t size() const { return mat.size(); } inline size_t size() const { return mat.size(); }
inline ssize_t size_s() const { return mat.size_s(); } inline ssize_t size_s() const { return mat.size_s(); }
inline size_t length() const { return mat.length(); } inline size_t length() const { return mat.length(); }
inline size_t capacity() const { return mat.capacity(); } inline size_t capacity() const { return mat.capacity(); }
inline bool isEmpty() const { return mat.isEmpty(); } inline bool isEmpty() const { return mat.isEmpty(); }
inline bool isNotEmpty() const { return mat.isNotEmpty(); }
class Row { class Row {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline Row(PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {st_ = p->cols_ * row; sz_ = p->cols_;} inline Row(PIVector2D<T> * p, size_t row): p_(&(p->mat)) {
st_ = p->cols_ * row;
sz_ = p->cols_;
}
PIVector<T> * p_; PIVector<T> * p_;
size_t st_, sz_; size_t st_, sz_;
public: public:
inline size_t size() const { return sz_; } inline size_t size() const { return sz_; }
inline T & operator[](size_t index) { return (*p_)[st_ + index]; } inline T & operator[](size_t index) { return (*p_)[st_ + index]; }
@@ -85,12 +98,12 @@ public:
inline const T * data(size_t index = 0) const { return p_->data(st_ + index); } inline const T * data(size_t index = 0) const { return p_->data(st_ + index); }
inline Row & operator=(const Row & other) { inline Row & operator=(const Row & other) {
if (p_ == other.p_ && st_ == other.st_) return *this; if (p_ == other.p_ && st_ == other.st_) return *this;
size_t sz = piMin<size_t>(sz_, other.sz_); const size_t sz = piMin<size_t>(sz_, other.sz_);
p_->_copyRaw(p_->data(st_), other.data(), sz); p_->_copyRaw(p_->data(st_), other.data(), sz);
return *this; return *this;
} }
inline Row & operator=(const PIVector<T> & other) { inline Row & operator=(const PIVector<T> & other) {
size_t sz = piMin<size_t>(sz, other.size()); const size_t sz = piMin<size_t>(sz_, other.size());
p_->_copyRaw(p_->data(st_), other.data(), sz); p_->_copyRaw(p_->data(st_), other.data(), sz);
return *this; return *this;
} }
@@ -99,10 +112,16 @@ public:
class Col { class Col {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline Col(PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {step_ = p->cols_; row_ = row; sz_ = p->rows_;} inline Col(PIVector2D<T> * p, size_t row): p_(&(p->mat)) {
step_ = p->cols_;
row_ = row;
sz_ = p->rows_;
}
PIVector<T> * p_; PIVector<T> * p_;
size_t step_, row_, sz_; size_t step_, row_, sz_;
public: public:
inline size_t size() const { return sz_; } inline size_t size() const { return sz_; }
inline T & operator[](size_t index) { return (*p_)[index * step_ + row_]; } inline T & operator[](size_t index) { return (*p_)[index * step_ + row_]; }
@@ -111,29 +130,37 @@ public:
inline const T * data(size_t index = 0) const { return p_->data(index * step_ + row_); } inline const T * data(size_t index = 0) const { return p_->data(index * step_ + row_); }
inline Col & operator=(const Col & other) { inline Col & operator=(const Col & other) {
if (p_ == other.p_ && row_ == other.row_) return *this; if (p_ == other.p_ && row_ == other.row_) return *this;
size_t sz = piMin<size_t>(sz_, other.sz_); const size_t sz = piMin<size_t>(sz_, other.sz_);
for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i]; for (int i = 0; i < sz; ++i)
(*p_)[i * step_ + row_] = other[i];
return *this; return *this;
} }
inline Row & operator=(const PIVector<T> & other) { inline Row & operator=(const PIVector<T> & other) {
size_t sz = piMin<size_t>(sz_, other.size()); const size_t sz = piMin<size_t>(sz_, other.size());
for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i]; for (int i = 0; i < sz; ++i)
(*p_)[i * step_ + row_] = other[i];
return *this; return *this;
} }
inline PIVector<T> toVector() const { inline PIVector<T> toVector() const {
PIVector<T> ret; PIVector<T> ret;
ret.reserve(sz_); ret.reserve(sz_);
for (size_t i=0; i<sz_; i++) ret << (*p_)[i * step_ + row_]; for (size_t i = 0; i < sz_; i++)
ret << (*p_)[i * step_ + row_];
return ret; return ret;
} }
}; };
class RowConst { class RowConst {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline RowConst(const PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {st_ = p->cols_ * row; sz_ = p->cols_;} inline RowConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)) {
st_ = p->cols_ * row;
sz_ = p->cols_;
}
const PIVector<T> * p_; const PIVector<T> * p_;
size_t st_, sz_; size_t st_, sz_;
public: public:
inline size_t size() const { return sz_; } inline size_t size() const { return sz_; }
inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; } inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; }
@@ -143,10 +170,16 @@ public:
class ColConst { class ColConst {
friend class PIVector2D<T>; friend class PIVector2D<T>;
private: private:
inline ColConst(const PIVector2D<T> * p, size_t row) : p_(&(p->mat)) {step_ = p->cols_; row_ = row; sz_ = p->rows_;} inline ColConst(const PIVector2D<T> * p, size_t row): p_(&(p->mat)) {
step_ = p->cols_;
row_ = row;
sz_ = p->rows_;
}
const PIVector<T> * p_; const PIVector<T> * p_;
size_t step_, row_, sz_; size_t step_, row_, sz_;
public: public:
inline size_t size() const { return p_->rows_; } inline size_t size() const { return p_->rows_; }
inline const T & operator[](size_t index) const { return (*p_)[index * step_ + row_]; } inline const T & operator[](size_t index) const { return (*p_)[index * step_ + row_]; }
@@ -154,7 +187,8 @@ public:
inline PIVector<T> toVector() const { inline PIVector<T> toVector() const {
PIVector<T> ret; PIVector<T> ret;
ret.reserve(sz_); ret.reserve(sz_);
for (int i=0; i<size(); i++) ret << (*p_)[i * step_ + row_]; for (int i = 0; i < size(); i++)
ret << (*p_)[i * step_ + row_];
return ret; return ret;
} }
}; };
@@ -172,24 +206,24 @@ public:
inline Col col(size_t index) { return Col(this, index); } inline Col col(size_t index) { return Col(this, index); }
inline ColConst col(size_t index) const { return ColConst(this, index); } inline ColConst col(size_t index) const { return ColConst(this, index); }
inline PIVector2D<T> & setRow(size_t row, const Row & other) { inline PIVector2D<T> & setRow(size_t row, const Row & other) {
size_t sz = piMin<size_t>(cols_, other.sz_); const size_t sz = piMin<size_t>(cols_, other.sz_);
mat._copyRaw(mat.data(cols_ * row), other.data(), sz); mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
return *this; return *this;
} }
inline PIVector2D<T> & setRow(size_t row, const RowConst & other) { inline PIVector2D<T> & setRow(size_t row, const RowConst & other) {
size_t sz = piMin<size_t>(cols_, other.sz_); const size_t sz = piMin<size_t>(cols_, other.sz_);
mat._copyRaw(mat.data(cols_ * row), other.data(), sz); mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
return *this; return *this;
} }
inline PIVector2D<T> & setRow(size_t row, const PIVector<T> & other) { inline PIVector2D<T> & setRow(size_t row, const PIVector<T> & other) {
size_t sz = piMin<size_t>(cols_, other.size()); const size_t sz = piMin<size_t>(cols_, other.size());
mat._copyRaw(mat.data(cols_ * row), other.data(), sz); mat._copyRaw(mat.data(cols_ * row), other.data(), sz);
return *this; return *this;
} }
inline PIVector2D<T> & addRow(const Row & other) { inline PIVector2D<T> & addRow(const Row & other) {
if (cols_ == 0) cols_ = other.sz_; if (cols_ == 0) cols_ = other.sz_;
size_t sz = piMin<size_t>(cols_, other.sz_); const size_t sz = piMin<size_t>(cols_, other.sz_);
size_t ps = mat.size(); const size_t ps = mat.size();
mat.resize(mat.size() + cols_); mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz); mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
@@ -197,8 +231,8 @@ public:
} }
inline PIVector2D<T> & addRow(const RowConst & other) { inline PIVector2D<T> & addRow(const RowConst & other) {
if (cols_ == 0) cols_ = other.sz_; if (cols_ == 0) cols_ = other.sz_;
size_t sz = piMin<size_t>(cols_, other.sz_); const size_t sz = piMin<size_t>(cols_, other.sz_);
size_t ps = mat.size(); const size_t ps = mat.size();
mat.resize(mat.size() + cols_); mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz); mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
@@ -206,8 +240,8 @@ public:
} }
inline PIVector2D<T> & addRow(const PIVector<T> & other) { inline PIVector2D<T> & addRow(const PIVector<T> & other) {
if (cols_ == 0) cols_ = other.size(); if (cols_ == 0) cols_ = other.size();
size_t sz = piMin<size_t>(cols_, other.size()); const size_t sz = piMin<size_t>(cols_, other.size());
size_t ps = mat.size(); const size_t ps = mat.size();
mat.resize(mat.size() + cols_); mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz); mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++; rows_++;
@@ -217,7 +251,7 @@ public:
inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) { inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) {
mat.resize(rows * cols_, f); mat.resize(rows * cols_, f);
rows_ = rows; rows_ = rows;
int cs = (cols - cols_); const int cs = (cols - cols_);
if (cs < 0) { if (cs < 0) {
for (size_t r = 0; r < rows; ++r) { for (size_t r = 0; r < rows; ++r) {
mat.remove(r * cols + cols, -cs); mat.remove(r * cols + cols, -cs);
@@ -237,22 +271,24 @@ public:
} }
inline bool operator==(const PIVector2D<T> & t) const { inline bool operator==(const PIVector2D<T> & t) const {
if (cols_ != t.cols_ || rows_ != t.rows_) if (cols_ != t.cols_ || rows_ != t.rows_) return false;
return false;
return mat == t.mat; return mat == t.mat;
} }
inline bool operator!=(const PIVector2D<T> & t) const { return !(*this == t); } inline bool operator!=(const PIVector2D<T> & t) const { return !(*this == t); }
PIVector<PIVector<T> > toVectors() const { inline PIVector<PIVector<T>> toVectors() const {
PIVector<PIVector<T>> ret; PIVector<PIVector<T>> ret;
ret.reserve(rows_); ret.reserve(rows_);
for (size_t i = 0; i < rows_; ++i) for (size_t i = 0; i < rows_; ++i)
ret << PIVector<T>(mat.data(i * cols_), cols_); ret << PIVector<T>(mat.data(i * cols_), cols_);
return ret; return ret;
} }
PIVector<T> toPlainVector() const {return mat;}
PIVector<T> & plainVector() {return mat;} inline PIVector<T> toPlainVector() const { return mat; }
const PIVector<T> & plainVector() const {return mat;}
inline PIVector<T> & plainVector() { return mat; }
inline const PIVector<T> & plainVector() const { return mat; }
inline void swap(PIVector2D<T> & other) { inline void swap(PIVector2D<T> & other) {
mat.swap(other.mat); mat.swap(other.mat);
@@ -260,9 +296,7 @@ public:
piSwap<size_t>(cols_, other.cols_); piSwap<size_t>(cols_, other.cols_);
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector2D<T> & _resizeRaw(size_t r, size_t c) { inline PIVector2D<T> & _resizeRaw(size_t r, size_t c) {
rows_ = r; rows_ = r;
cols_ = c; cols_ = c;
@@ -275,11 +309,14 @@ public:
mat.clear(); mat.clear();
} }
void forEach(std::function<void(const T &)> f) const { template<typename ST>
mat.forEach(f); inline PIVector2D<ST> map(std::function<ST(const T & e)> f) const {
return PIVector2D<ST>(rows_, cols_, mat.map(f));
} }
PIVector2D<T> & forEach(std::function<void(T &)> f) { inline void forEach(std::function<void(const T &)> f) const { mat.forEach(f); }
inline PIVector2D<T> & forEach(std::function<void(T &)> f) {
mat.forEach(f); mat.forEach(f);
return *this; return *this;
} }

View File

@@ -34,376 +34,22 @@
#ifndef PIBASE_H #ifndef PIBASE_H
#define PIBASE_H #define PIBASE_H
#include "pip_version.h" #include "pibase_macros.h"
#include "piplatform.h" #include "pimemoryblock.h"
#include "pip_export.h" #include "pip_export.h"
#include "pip_defs.h"
#include <string.h> #include <string.h>
//! \~english
//! Meta-information section for any entity.
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
//! Contains sequence of key=value pairs, e.g.
//! \~russian
//! Секция метаинформации для любой сущности.
//! Парсится \a pip_cmg и доступна с помощью \a PICodeInfo.
//! Содержит набор пар ключ=значение, например
//! \~
//! PIMETA(id=12345,tag="my string")
#define PIMETA(...)
#ifdef DOXYGEN
//! \~\brief
//! \~english Major value of PIP version
//! \~russian Мажорная версия PIP
# define PIP_VERSION_MAJOR
//! \~\brief
//! \~english Minor value of PIP version
//! \~russian Минорная версия PIP
# define PIP_VERSION_MINOR
//! \~\brief
//! \~english Revision value of PIP version
//! \~russian Ревизия версии PIP
# define PIP_VERSION_REVISION
//! \~\brief
//! \~english Suffix of PIP version
//! \~russian Суффикс версии PIP
# define PIP_VERSION_SUFFIX
//! \~\brief
//! \~english Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
//! \~russian Версия PIP в hex - 0x##(Major)##(Minor)##(Revision)
# define PIP_VERSION
//! \~\brief
//! \~english Macro is defined when compile-time debug is enabled
//! \~russian Макрос объявлен когда включена compile-time отладка
# define PIP_DEBUG
//! \~\brief
//! \~english Macro is defined when operation system is any Windows
//! \~russian Макрос объявлен когда операционная система Windows
# define WINDOWS
//! \~\brief
//! \~english Macro is defined when operation system is QNX or Blackberry
//! \~russian Макрос объявлен когда операционная система QNX или Blackberry
# define QNX
//! \~\brief
//! \~english Macro is defined when operation system is Blackberry
//! \~russian Макрос объявлен когда операционная система Blackberry
# define BLACKBERRY
//! \~\brief
//! \~english Macro is defined when operation system is FreeBSD
//! \~russian Макрос объявлен когда операционная система FreeBSD
# define FREE_BSD
//! \~\brief
//! \~english Macro is defined when operation system is Mac OS
//! \~russian Макрос объявлен когда операционная система Mac OS
# define MAC_OS
//! \~\brief
//! \~english Macro is defined when operation system is Android
//! \~russian Макрос объявлен когда операционная система Android
# define ANDROID
//! \~\brief
//! \~english Macro is defined when operation system is any Linux
//! \~russian Макрос объявлен когда операционная система Linux
# define LINUX
//! \~\brief
//! \~english Macro is defined when operation system is FreeRTOS
//! \~russian Макрос объявлен когда операционная система FreeRTOS
# define FREERTOS
//! \~\brief
//! \~english Macro is defined when compiler is GCC or MinGW
//! \~russian Макрос объявлен когда компилятор GCC или MinGW
# define CC_GCC
//! \~\brief
//! \~english Macro is defined when PIP is decided that host is support language
//! \~russian Макрос объявлен когда PIP решил что система поддерживает локализацию
# define HAS_LOCALE
//! \~\brief
//! \~english Macro is defined when PIP is building for embedded systems
//! \~russian Макрос объявлен когда PIP собирается для встраиваемых систем
# define MICRO_PIP
//! \~\brief
//! \~english Macro is defined when compiler is Visual Studio
//! \~russian Макрос объявлен когда компилятор Visual Studio
# define CC_VC
//! \~\brief
//! \~english Macro is defined when compiler is AVR GCC
//! \~russian Макрос объявлен когда компилятор AVR GCC
# define CC_AVR_GCC
//! \~\brief
//! \~english Macro is defined when compiler is unknown
//! \~russian Макрос объявлен когда компилятор неизвестен
# define CC_OTHER
//! \~\brief
//! \~english Macro is defined when PIP can use "rt" library for \a PITimer::ThreadRT timers implementation
//! \~russian Макрос объявлен когда PIP может использовать библиотеку "rt" для \a PITimer::ThreadRT реализации таймера
# define PIP_TIMER_RT
//! \~\brief
//! \~english Macro to declare private section, "export" is optional
//! \~russian Макрос для объявления частной секции, "export" необязателен
# define PRIVATE_DECLARATION(export)
//! \~\brief
//! \~english Macro to start definition of private section
//! \~russian Макрос для начала реализации частной секции
# define PRIVATE_DEFINITION_START(Class)
//! \~\brief
//! \~english Macro to end definition of private section
//! \~russian Макрос для окончания реализации частной секции
# define PRIVATE_DEFINITION_END(Class)
//! \~\brief
//! \~english Macro to access private section by pointer
//! \~russian Макрос для доступа к частной секции
# define PRIVATE
//! \~\brief
//! \~english Macro to access private section by pointer without brakes ()
//! \~russian Макрос для доступа к частной секции без обрамляющих скобок ()
# define PRIVATEWB
//! \~\brief
//! \~english Macro to start static initializer
//! \~russian Макрос для начала статической инициализации
# define STATIC_INITIALIZER_BEGIN
//! \~\brief
//! \~english Macro to end static initializer
//! \~russian Макрос для окончания статической инициализации
# define STATIC_INITIALIZER_END
#undef MICRO_PIP
#undef FREERTOS
#endif //DOXYGEN
#ifdef CC_AVR_GCC #ifdef CC_AVR_GCC
# include <ArduinoSTL.h> # include <ArduinoSTL.h>
#endif #endif
#include <functional>
#include <cstddef>
#include <cassert>
#include <limits>
#include <atomic> #include <atomic>
#include <cassert>
#ifdef WINDOWS #include <cstddef>
# ifdef CC_VC #include <cstdio>
# define SHUT_RDWR 2 #include <functional>
# pragma comment(lib, "Ws2_32.lib") #include <initializer_list>
# pragma comment(lib, "Iphlpapi.lib") #include <limits>
# pragma comment(lib, "Psapi.lib")
# ifdef ARCH_BITS_32
# define _X86_
# else
# define _IA64_
# endif
# else
# define SHUT_RDWR SD_BOTH
# endif
typedef int socklen_t;
extern long long __pi_perf_freq;
#endif
#ifndef DOXYGEN
#ifdef ANDROID
///# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
//inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
//inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
#endif
#ifdef MAC_OS
# define environ (*_NSGetEnviron())
typedef long time_t;
#endif
#ifdef LINUX
# define environ __environ
#endif
#ifdef FREE_BSD
extern char ** environ;
#endif
#ifndef NO_UNUSED
# define NO_UNUSED(x) (void)x
#endif
#ifndef assert
# define assert(x)
# define assertm(exp, msg)
#else
# define assertm(exp, msg) assert(((void)msg, exp))
#endif
#ifdef MICRO_PIP
# define __PIP_TYPENAME__(T) "?"
#else
# define __PIP_TYPENAME__(T) typeid(T).name()
#endif
#ifdef CC_GCC
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED __attribute__((deprecated))
# define DEPRECATEDM(msg) __attribute__((deprecated(msg)))
# if CC_GCC_VERSION > 0x025F // > 2.95
# pragma GCC diagnostic warning "-Wdeprecated-declarations"
# ifdef LINUX
# define HAS_LOCALE
# endif
# ifdef MAC_OS
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# endif
# endif
# ifdef ANDROID
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wextra"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
//# pragma GCC diagnostic ignored "-Wliteral-suffix"
# endif
#endif
#ifdef CC_VC
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED __declspec(deprecated)
# define DEPRECATEDM(msg) __declspec(deprecated(msg))
# pragma warning(disable: 4018)
# pragma warning(disable: 4061)
# pragma warning(disable: 4100)
# pragma warning(disable: 4239)
# pragma warning(disable: 4242)
# pragma warning(disable: 4244)
# pragma warning(disable: 4251)
# pragma warning(disable: 4365)
# pragma warning(disable: 4512)
# pragma warning(disable: 4668)
# pragma warning(disable: 4710)
# pragma warning(disable: 4800)
# pragma warning(disable: 4820)
# pragma warning(disable: 4986)
# pragma warning(disable: 4996)
# ifdef ARCH_BITS_32
typedef long ssize_t;
# else
typedef long long ssize_t;
# endif
#endif
#ifdef CC_OTHER
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED
# define DEPRECATEDM(msg)
#endif
#endif //DOXYGEN
// Private data macros
#ifndef DOXYGEN
#define PRIVATE_DECLARATION(e) \
struct __Private__; \
friend struct __Private__; \
struct e __PrivateInitializer__ { \
__PrivateInitializer__(); \
__PrivateInitializer__(const __PrivateInitializer__ & o); \
~__PrivateInitializer__(); \
__PrivateInitializer__ & operator =(const __PrivateInitializer__ & o); \
__Private__ * p; \
}; \
__PrivateInitializer__ __privateinitializer__;
#define PRIVATE_DEFINITION_START(c) \
struct c::__Private__ {
#define PRIVATE_DEFINITION_END(c) \
}; \
c::__PrivateInitializer__::__PrivateInitializer__() {p = new c::__Private__();} \
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ & ) {/*if (p) delete p;*/ p = new c::__Private__();} \
c::__PrivateInitializer__::~__PrivateInitializer__() {delete p; p = 0;} \
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator =(const c::__PrivateInitializer__ & ) {if (p) delete p; p = new c::__Private__(); return *this;}
#define PRIVATE (__privateinitializer__.p)
#define PRIVATEWB __privateinitializer__.p
#endif //DOXYGEN
#define NO_COPY_CLASS(name) \
name(const name&) = delete; \
name& operator=(const name&) = delete;
#define _PIP_ADD_COUNTER_WS(a, cnt) a##cnt
#define _PIP_ADD_COUNTER_WF(a, cnt) _PIP_ADD_COUNTER_WS(a, cnt)
#define _PIP_ADD_COUNTER(a) _PIP_ADD_COUNTER_WF(a, __COUNTER__)
#define STATIC_INITIALIZER_BEGIN \
class { \
class _Initializer_ { \
public: \
_Initializer_() {
#define STATIC_INITIALIZER_END \
} \
} _initializer_; \
} _PIP_ADD_COUNTER(_pip_initializer_);
//! \~\brief
//! \~english Minimal sleep in milliseconds for internal PIP using
//! \~russian Минимальное значание задержки в милисекундах для внутреннего использования в библиотеке PIP
//! \~\details
//! \~english Using in \a piMinSleep(), \a PIThread, \a PITimer::Pool. By default 1ms.
//! \~russian Используется в \a piMinSleep(), \a PIThread, \a PITimer::Pool. По умолчанию равна 1мс.
#ifndef PIP_MIN_MSLEEP
# ifndef MICRO_PIP
# define PIP_MIN_MSLEEP 1.
# else
# define PIP_MIN_MSLEEP 10.
# endif
#endif
//! \~\brief
//! \~english Macro used for infinite loop
//! \~russian Макрос для бесконечного цикла
#define FOREVER for (;;)
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define FOREVER_WAIT FOREVER piMinSleep();
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define WAIT_FOREVER FOREVER piMinSleep();
//! \~\brief //! \~\brief
//! \~english Global variable enabling output to piCout, default is true //! \~english Global variable enabling output to piCout, default is true
@@ -431,7 +77,12 @@ typedef long double ldouble;
//! \~\details //! \~\details
//! \~english Example:\n \snippet piincludes.cpp swap //! \~english Example:\n \snippet piincludes.cpp swap
//! \~russian Пример:\n \snippet piincludes.cpp swap //! \~russian Пример:\n \snippet piincludes.cpp swap
template<typename T> inline void piSwap(T & f, T & s) {T t(std::move(f)); f = std::move(s); s = std::move(t);} template<typename T>
inline void piSwap(T & f, T & s) {
T t(std::move(f));
f = std::move(s);
s = std::move(t);
}
//! \~\brief //! \~\brief
//! \~english Templated function for swap two values without "=" //! \~english Templated function for swap two values without "="
@@ -439,7 +90,8 @@ template<typename T> inline void piSwap(T & f, T & s) {T t(std::move(f)); f = st
//! \~\details //! \~\details
//! \~english Example:\n \snippet piincludes.cpp swapBinary //! \~english Example:\n \snippet piincludes.cpp swapBinary
//! \~russian Пример:\n \snippet piincludes.cpp swapBinary //! \~russian Пример:\n \snippet piincludes.cpp swapBinary
template<typename T> inline void piSwapBinary(T & f, T & s) { template<typename T>
inline void piSwapBinary(T & f, T & s) {
if ((size_t *)&f == (size_t *)&s) return; if ((size_t *)&f == (size_t *)&s) return;
size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T); size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
size_t i = 0; size_t i = 0;
@@ -455,7 +107,8 @@ template<typename T> inline void piSwapBinary(T & f, T & s) {
} }
} }
template<> inline void piSwapBinary(const void *& f, const void *& s) { template<>
inline void piSwapBinary(const void *& f, const void *& s) {
if ((size_t *)f == (size_t *)s) return; if ((size_t *)f == (size_t *)s) return;
size_t j = (sizeof(void *) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(void *); size_t j = (sizeof(void *) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(void *);
size_t i = 0; size_t i = 0;
@@ -480,10 +133,7 @@ template<> inline void piSwapBinary(const void *& f, const void *& s) {
//! \~english Example:\n \snippet piincludes.cpp compareBinary //! \~english Example:\n \snippet piincludes.cpp compareBinary
//! \~russian Пример:\n \snippet piincludes.cpp compareBinary //! \~russian Пример:\n \snippet piincludes.cpp compareBinary
inline bool piCompareBinary(const void * f, const void * s, size_t size) { inline bool piCompareBinary(const void * f, const void * s, size_t size) {
for (size_t i = 0; i < size; ++i) return 0 == memcmp(f, s, size);
if (((const uchar*)f)[i] != ((const uchar*)s)[i])
return false;
return true;
} }
//! \~\brief //! \~\brief
@@ -506,7 +156,10 @@ inline bool piCompareBinary(const void * f, const void * s, size_t size) {
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp round //! \snippet piincludes.cpp round
template<typename T> inline constexpr int piRound(const T & v) {return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));} template<typename T>
inline constexpr int piRound(const T & v) {
return int(v >= T(0.) ? v + T(0.5) : v - T(0.5));
}
//! \~\brief //! \~\brief
//! \~english Templated function return floor of float falue //! \~english Templated function return floor of float falue
@@ -528,7 +181,10 @@ template<typename T> inline constexpr int piRound(const T & v) {return int(v >=
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp floor //! \snippet piincludes.cpp floor
template<typename T> inline constexpr int piFloor(const T & v) {return v < T(0) ? int(v) - 1 : int(v);} template<typename T>
inline constexpr int piFloor(const T & v) {
return v < T(0) ? int(v) - 1 : int(v);
}
//! \~\brief //! \~\brief
//! \~english Templated function return ceil of float falue //! \~english Templated function return ceil of float falue
@@ -550,7 +206,10 @@ template<typename T> inline constexpr int piFloor(const T & v) {return v < T(0)
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp ceil //! \snippet piincludes.cpp ceil
template<typename T> inline constexpr int piCeil(const T & v) {return v < T(0) ? int(v) : int(v) + 1;} template<typename T>
inline constexpr int piCeil(const T & v) {
return v < T(0) ? int(v) : int(v) + 1;
}
//! \~\brief //! \~\brief
//! \~english Templated function return absolute of numeric falue //! \~english Templated function return absolute of numeric falue
@@ -580,11 +239,20 @@ template<typename T> inline constexpr int piCeil(const T & v) {return v < T(0) ?
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp abs //! \snippet piincludes.cpp abs
template<typename T> inline constexpr T piAbs(const T & v) {return (v >= T(0) ? v : -v);} template<typename T>
inline constexpr T piAbs(const T & v) {
return (v >= T(0) ? v : -v);
}
template<typename T>
constexpr T piMin(const T & f, const T & s) {
return ((f > s) ? s : f);
}
//! \~\brief //! \~\brief
//! \~english Templated function return minimum of two values //! \~english Templated function return minimum of several values
//! \~russian Шаблонный метод, возвращающий минимум из двух значений //! \~russian Шаблонный метод, возвращающий минимум из нескольких значений
//! \~\details //! \~\details
//! \~english //! \~english
//! There are some macros: //! There are some macros:
@@ -608,39 +276,20 @@ template<typename T> inline constexpr T piAbs(const T & v) {return (v >= T(0) ?
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp min2 //! \snippet piincludes.cpp min2
template<typename T> inline constexpr T piMin(const T & f, const T & s) {return ((f > s) ? s : f);} template<typename T, typename... Args>
constexpr T piMin(const T & f, const T & s, const Args &... args) {
return piMin<T>(piMin<T>(f, s), args...);
}
template<typename T>
constexpr T piMax(const T & f, const T & s) {
return ((f < s) ? s : f);
}
//! \~\brief //! \~\brief
//! \~english Templated function return minimum of tree values //! \~english Templated function return maximum of several values
//! \~russian Шаблонный метод, возвращающий минимум из трех значений //! \~russian Шаблонный метод, возвращающий максимум из нескольких значений
//! \~\details
//! \~english
//! There are some macros:
//! - \c piMins for "short"
//! - \c piMini for "int"
//! - \c piMinl for "long"
//! - \c piMinll for "llong"
//! - \c piMinf for "float"
//! - \c piMind for "double"
//!
//! Example:
//! \snippet piincludes.cpp min3
//! \~russian
//! Есть несколько макросов:
//! - \c piMins для "short"
//! - \c piMini для "int"
//! - \c piMinl для "long"
//! - \c piMinll для "llong"
//! - \c piMinf для "float"
//! - \c piMind для "double"
//!
//! Пример:
//! \snippet piincludes.cpp min3
template<typename T> inline constexpr T piMin(const T & f, const T & s, const T & t) {return ((f < s && f < t) ? f : ((s < t) ? s : t));}
//! \~\brief
//! \~english Templated function return maximum of two values
//! \~russian Шаблонный метод, возвращающий максимум из двух значений
//! \~\details //! \~\details
//! \~english //! \~english
//! There are some macros: //! There are some macros:
@@ -664,35 +313,11 @@ template<typename T> inline constexpr T piMin(const T & f, const T & s, const T
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp max2 //! \snippet piincludes.cpp max2
template<typename T> inline constexpr T piMax(const T & f, const T & s) {return ((f < s) ? s : f);} template<typename T, typename... Args>
constexpr T piMax(const T & f, const T & s, const Args &... args) {
return piMax<T>(piMax<T>(f, s), args...);
}
//! \~\brief
//! \~english Templated function return maximum of tree values
//! \~russian Шаблонный метод, возвращающий максимум из трех значений
//! \~\details
//! \~english
//! There are some macros:
//! - \c piMaxs for "short"
//! - \c piMaxi for "int"
//! - \c piMaxl for "long"
//! - \c piMaxll for "llong"
//! - \c piMaxf for "float"
//! - \c piMaxd for "double"
//!
//! Example:
//! \snippet piincludes.cpp max3
//! \~russian
//! Есть несколько макросов:
//! - \c piMaxs для "short"
//! - \c piMaxi для "int"
//! - \c piMaxl для "long"
//! - \c piMaxll для "llong"
//! - \c piMaxf для "float"
//! - \c piMaxd для "double"
//!
//! Пример:
//! \snippet piincludes.cpp max3
template<typename T> inline constexpr T piMax(const T & f, const T & s, const T & t) {return ((f > s && f > t) ? f : ((s > t) ? s : t));}
//! \~\brief //! \~\brief
//! \~english Templated function return clamped value //! \~english Templated function return clamped value
@@ -722,14 +347,9 @@ template<typename T> inline constexpr T piMax(const T & f, const T & s, const T
//! //!
//! Пример: //! Пример:
//! \snippet piincludes.cpp clamp //! \snippet piincludes.cpp clamp
template<typename T> inline constexpr T piClamp(const T & v, const T & min, const T & max) {return (v > max ? max : (v < min ? min : v));} template<typename T>
inline constexpr T piClamp(const T & v, const T & min, const T & max) {
//! \~\brief return (v > max ? max : (v < min ? min : v));
//! \~english Function inverse byte order in memory block ([1..N] -> [N..1])
//! \~russian Метод для смены порядка байт в блоке памяти ([1..N] -> [N..1])
inline void piLetobe(void * data, int size) {
for (int i = 0; i < size / 2; i++)
piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[i]);
} }
//! \~\brief //! \~\brief
@@ -755,51 +375,98 @@ inline bool piCompare(const T & a, const T & b, const T & epsilon = std::numeric
return piAbs(a - b) <= epsilon; return piAbs(a - b) <= epsilon;
} }
// Endians
//! \~\brief
//! \~english Function inverse byte order in memory block ([1..N] -> [N..1])
//! \~russian Метод для смены порядка байт в блоке памяти ([1..N] -> [N..1])
inline void piChangeEndianBinary(void * data, size_t size) {
auto hs = size / 2;
for (size_t i = 0; i < hs; i++)
piSwap<uchar>(((uchar *)data)[size - i - 1], ((uchar *)data)[i]);
}
//! \~\brief
//! \~english Function inverse byte order in memory block ([1..N] -> [N..1])
//! \~russian Метод для смены порядка байт в блоке памяти ([1..N] -> [N..1])
inline void piChangeEndianBinary(PIMemoryBlock mem_blk) {
if (mem_blk.isNull()) return;
piChangeEndianBinary(mem_blk.data(), mem_blk.size());
}
//! \~\brief //! \~\brief
//! \~english Templated function that inverse byte order of value "v" //! \~english Templated function that inverse byte order of value "v"
//! \~russian Шаблонный метод, меняющий порядок байт в переменной "v" //! \~russian Шаблонный метод, меняющий порядок байт в переменной "v"
template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));} template<typename T>
inline void piChangeEndian(T & v);
//! \~\brief //! \~\brief
//! \~english Templated function that returns "v" with inversed byte order //! \~english Templated function that returns value "v" with inversed byte order
//! \~russian Шаблонный метод, возвращающий переменную "v" с измененным порядком байт //! \~russian Шаблонный метод, возвращающий значение "v" с измененным порядком байт
//! \~\details template<typename T>
//! \~english inline T piChangedEndian(const T & v);
//! This function used to convert values between little and big endian \n
//! There are some macros:
//! - \c piLetobes for "ushort"
//! - \c piLetobei for "uint"
//! - \c piLetobel for "ulong"
//! - \c piLetobell for "ullong"
//!
//! Example:
//! \snippet piincludes.cpp letobe
//! \~russian
//! Этот метод используется для изменения порядка байт между little и big endian
//! Есть несколько макросов:
//! - \c piLetobes для "ushort"
//! - \c piLetobei для "uint"
//! - \c piLetobel для "ulong"
//! - \c piLetobell для "ullong"
//!
//! Пример:
//! \snippet piincludes.cpp letobe
template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
// specialization
template<> inline uint16_t piLetobe(const uint16_t & v) {return (v << 8) | (v >> 8);} template<typename T>
template<> inline uint32_t piLetobe(const uint32_t & v) {return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);} inline void piChangeEndian(T & v) {
template<> inline float piLetobe(const float & v) { piChangeEndianBinary(&v, sizeof(T));
union _pletobe_f {
_pletobe_f(const float &f_) {f = f_;}
float f;
uint32_t v;
};
_pletobe_f a(v);
a.v = (a.v >> 24) | ((a.v >> 8) & 0xFF00) | ((a.v << 8) & 0xFF0000) | ((a.v << 24) & 0xFF000000);
return a.f;
} }
template<typename T>
inline T piChangedEndian(const T & v) {
T ret = v;
piChangeEndianBinary(&ret, sizeof(T));
return ret;
}
template<>
inline uint16_t piChangedEndian(const uint16_t & v) {
return (v << 8) | (v >> 8);
}
template<>
inline uint32_t piChangedEndian(const uint32_t & v) {
return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000);
}
template<>
inline float piChangedEndian(const float & v) {
union {
float f;
uint32_t i;
} u;
u.f = v;
u.i = piChangedEndian(u.i);
return u.f;
}
template<>
inline void piChangeEndian(uint16_t & v) {
v = piChangedEndian(v);
}
template<>
inline void piChangeEndian(uint32_t & v) {
v = piChangedEndian(v);
}
template<>
inline void piChangeEndian(float & v) {
v = piChangedEndian(v);
}
DEPRECATEDM("use piChangeEndianBinary()")
inline void piLetobe(void * data, int size) {
piChangeEndianBinary(data, size);
}
template<typename T>
DEPRECATEDM("use piChangedEndian()")
inline T piLetobe(const T & v) {
return piChangedEndian(v);
}
//! \~\brief //! \~\brief
//! \~english Generic hash function, implements murmur3/32 algorithm //! \~english Generic hash function, implements murmur3/32 algorithm
//! \~russian Хэш-функция общего назначения, по алгоритму murmur3/32 //! \~russian Хэш-функция общего назначения, по алгоритму murmur3/32
@@ -842,21 +509,115 @@ inline uint piHashData(const uchar * data, uint len, uint seed = 0) {
} }
template<typename T> inline uint piHash(const T & v) { template<typename T>
inline uint piHash(const T & v) {
return 0; return 0;
} }
template<> inline uint piHash(const char & v) {return (uint)v;} template<>
template<> inline uint piHash(const uchar & v) {return (uint)v;} inline uint piHash(const char & v) {
template<> inline uint piHash(const short & v) {return (uint)v;} return (uint)v;
template<> inline uint piHash(const ushort & v) {return (uint)v;} }
template<> inline uint piHash(const int & v) {return (uint)v;} template<>
template<> inline uint piHash(const uint & v) {return (uint)v;} inline uint piHash(const uchar & v) {
template<> inline uint piHash(const llong & v) {return piHashData((const uchar *)&v, sizeof(v));} return (uint)v;
template<> inline uint piHash(const ullong & v) {return piHashData((const uchar *)&v, sizeof(v));} }
template<> inline uint piHash(const float & v) {return (uint)v;} template<>
template<> inline uint piHash(const double & v) {return piHashData((const uchar *)&v, sizeof(v));} inline uint piHash(const short & v) {
template<> inline uint piHash(const ldouble & v) {return piHashData((const uchar *)&v, sizeof(v));} return (uint)v;
}
template<>
inline uint piHash(const ushort & v) {
return (uint)v;
}
template<>
inline uint piHash(const int & v) {
return (uint)v;
}
template<>
inline uint piHash(const uint & v) {
return (uint)v;
}
template<>
inline uint piHash(const llong & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
template<>
inline uint piHash(const ullong & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
template<>
inline uint piHash(const float & v) {
return (uint)v;
}
template<>
inline uint piHash(const double & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
template<>
inline uint piHash(const ldouble & v) {
return piHashData((const uchar *)&v, sizeof(v));
}
//! \~\brief
//! \~english Zero "size" bytes by address "ptr".
//! \~russian Зануляет "size" байт по адресу "ptr".
inline void piZeroMemory(void * ptr, size_t size) {
memset(ptr, 0, size);
}
//! \~\brief
//! \~english Zero variable "v" memory.
//! \~russian Зануляет память переменной "v".
template<typename T>
inline void piZeroMemory(T & v) {
piZeroMemory(&v, sizeof(v));
}
//! \~\brief
//! \~english Call \b delete on each "container" element.
//! \~russian Вызывает \b delete на каждый элемент "container".
template<typename T>
inline void piDeleteAll(const T & container) {
for (auto i: container) {
delete i;
}
}
//! \~\brief
//! \~english Call \b delete on each element of
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Вызывает \b delete на каждый элемент
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
template<typename T>
inline void piDeleteAll(std::initializer_list<T> container) {
for (auto i: container) {
delete i;
}
}
//! \~\brief
//! \~english Call \b delete on each "container" element and clear container.
//! \~russian Вызывает \b delete на каждый элемент "container" и очищает контейнер.
template<typename T>
inline void piDeleteAllAndClear(T & container) {
piDeleteAll(container);
container.clear();
}
//! \~\brief
//! \~english Call \b delete if "pointer" is not null and set it to null. Returns if deleted.
//! \~russian Вызывает \b delete на "pointer" если он не нулевой и устанавливает его в ноль. Возвращает было ли удаление.
template<typename T>
inline bool piDeleteSafety(T *& pointer) {
if (!pointer) return false;
delete pointer;
pointer = nullptr;
return true;
}
#define piRoundf piRound<float> #define piRoundf piRound<float>
#define piRoundd piRound<double> #define piRoundd piRound<double>
@@ -897,4 +658,98 @@ template<> inline uint piHash(const ldouble & v) {return piHashData((const uchar
#define piLetobef piLetobe<float> #define piLetobef piLetobe<float>
//! \~\brief
//! \~english Class for executing a function upon scope exit
//! \~russian Класс для выполнения функции при выходе из области видимости
//! \~\details
//! \~english Example
//! \~russian Пример
//! \~\code
//! bool yourFunc() {
//! PIScopeExitCall error_call([]() { piCout << "Error!"; });
//! ...
//! if (!good0) {
//! ...
//! return false;
//! }
//! if (!good1) {
//! ...
//! return false;
//! }
//! ...
//! error_call.cancel();
//! return true;
//! }
//! \endcode
//! \~english In this example "Error!" will be printed on every \b false function return.
//! \~russian В данном примере будет выведен "Error!" при каждом \b false возврате из функции.
class PIP_EXPORT PIScopeExitCall {
public:
//! \~\brief
//! \~english Constructor that takes a function to execute
//! \~russian Конструктор, который принимает функцию для выполнения
explicit PIScopeExitCall(std::function<void()> f): func(f) {}
//! \~\brief
//! \~english Destructor that executes the function if it exists
//! \~russian Деструктор, который выполняет функцию, если она существует
~PIScopeExitCall() { call(); }
//! \~\brief
//! \~english Method for canceling the function
//! \~russian Метод для отмены функции
void cancel() { func = nullptr; }
//! \~\brief
//! \~english Method for call the function
//! \~russian Метод для вызова функции
void call() {
if (func) func();
}
//! \~\brief
//! \~english Method for call and canceling the function
//! \~russian Метод для вызова и отмены функции
void callAndCancel() {
call();
cancel();
}
private:
NO_COPY_CLASS(PIScopeExitCall)
std::function<void()> func;
};
//! \~\brief
//! \~english Inherit from this class to make your class non-trivially copyable.
//! \~russian Наследуйтесь от этого класса чтобы сделать свой класс нетривиально копируемым.
struct PIP_EXPORT PINonTriviallyCopyable {
PINonTriviallyCopyable() noexcept = default;
PINonTriviallyCopyable(const PINonTriviallyCopyable &) noexcept = default;
PINonTriviallyCopyable(PINonTriviallyCopyable &&) noexcept;
PINonTriviallyCopyable & operator=(const PINonTriviallyCopyable &) noexcept = default;
PINonTriviallyCopyable & operator=(PINonTriviallyCopyable &&) noexcept = default;
~PINonTriviallyCopyable() = default;
};
inline PINonTriviallyCopyable::PINonTriviallyCopyable(PINonTriviallyCopyable &&) noexcept = default;
template<typename T>
struct FunctionType {
using Type = void;
};
template<typename Ret, typename Class, typename... Args>
struct FunctionType<Ret (Class::*)(Args...) const> {
using Type = std::function<Ret(Args...)>;
};
template<typename L>
typename FunctionType<decltype(&L::operator())>::Type toStdFunction(L const & func) {
return func;
}
#endif // PIBASE_H #endif // PIBASE_H

View File

@@ -0,0 +1,413 @@
/*! \file pibase_macros.h
* \ingroup Core
* \~\brief
* \~english Base macros
* \~russian Базовые макросы
*
* \~\details
* \~english
* This file declares basic useful maros
* \~russian
* Этот файл объявляет основные вспомогательные макросы
*/
/*
PIP - Platform Independent Primitives
Base macros
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBASE_MACROS_H
#define PIBASE_MACROS_H
#include "pip_defs.h"
#include "pip_version.h"
#include "piplatform.h"
//! \~english
//! Meta-information section for any entity.
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
//! Contains sequence of key=value pairs, e.g.
//! \~russian
//! Секция метаинформации для любой сущности.
//! Парсится \a pip_cmg и доступна с помощью \a PICodeInfo.
//! Содержит набор пар ключ=значение, например
//! \~
//! PIMETA(id=12345,tag="my string")
#define PIMETA(...)
#ifdef DOXYGEN
//! \~\brief
//! \~english Major value of PIP version
//! \~russian Мажорная версия PIP
# define PIP_VERSION_MAJOR
//! \~\brief
//! \~english Minor value of PIP version
//! \~russian Минорная версия PIP
# define PIP_VERSION_MINOR
//! \~\brief
//! \~english Revision value of PIP version
//! \~russian Ревизия версии PIP
# define PIP_VERSION_REVISION
//! \~\brief
//! \~english Suffix of PIP version
//! \~russian Суффикс версии PIP
# define PIP_VERSION_SUFFIX
//! \~\brief
//! \~english Version of PIP in hex - 0x##(Major)##(Minor)##(Revision)
//! \~russian Версия PIP в hex - 0x##(Major)##(Minor)##(Revision)
# define PIP_VERSION
//! \~\brief
//! \~english Macro is defined when compile-time debug is enabled
//! \~russian Макрос объявлен когда включена compile-time отладка
# define PIP_DEBUG
//! \~\brief
//! \~english Macro is defined when operation system is any Windows
//! \~russian Макрос объявлен когда операционная система Windows
# define WINDOWS
//! \~\brief
//! \~english Macro is defined when operation system is QNX or Blackberry
//! \~russian Макрос объявлен когда операционная система QNX или Blackberry
# define QNX
//! \~\brief
//! \~english Macro is defined when operation system is Blackberry
//! \~russian Макрос объявлен когда операционная система Blackberry
# define BLACKBERRY
//! \~\brief
//! \~english Macro is defined when operation system is FreeBSD
//! \~russian Макрос объявлен когда операционная система FreeBSD
# define FREE_BSD
//! \~\brief
//! \~english Macro is defined when operation system is Mac OS
//! \~russian Макрос объявлен когда операционная система Mac OS
# define MAC_OS
//! \~\brief
//! \~english Macro is defined when operation system is Android
//! \~russian Макрос объявлен когда операционная система Android
# define ANDROID
//! \~\brief
//! \~english Macro is defined when operation system is any Linux
//! \~russian Макрос объявлен когда операционная система Linux
# define LINUX
//! \~\brief
//! \~english Macro is defined when operation system is FreeRTOS
//! \~russian Макрос объявлен когда операционная система FreeRTOS
# define FREERTOS
//! \~\brief
//! \~english Macro is defined when compiler is GCC or MinGW
//! \~russian Макрос объявлен когда компилятор GCC или MinGW
# define CC_GCC
//! \~\brief
//! \~english Macro is defined when PIP is decided that host is support language
//! \~russian Макрос объявлен когда PIP решил что система поддерживает локализацию
# define HAS_LOCALE
//! \~\brief
//! \~english Macro is defined when PIP is building for embedded systems
//! \~russian Макрос объявлен когда PIP собирается для встраиваемых систем
# define MICRO_PIP
//! \~\brief
//! \~english Macro is defined when compiler is Visual Studio
//! \~russian Макрос объявлен когда компилятор Visual Studio
# define CC_VC
//! \~\brief
//! \~english Macro is defined when compiler is AVR GCC
//! \~russian Макрос объявлен когда компилятор AVR GCC
# define CC_AVR_GCC
//! \~\brief
//! \~english Macro is defined when compiler is unknown
//! \~russian Макрос объявлен когда компилятор неизвестен
# define CC_OTHER
//! \~\brief
//! \~english Macro to declare private section, "export" is optional
//! \~russian Макрос для объявления частной секции, "export" необязателен
# define PRIVATE_DECLARATION(export)
//! \~\brief
//! \~english Macro to start definition of private section
//! \~russian Макрос для начала реализации частной секции
# define PRIVATE_DEFINITION_START(Class)
//! \~\brief
//! \~english Macro to end definition of private section
//! \~russian Макрос для окончания реализации частной секции
# define PRIVATE_DEFINITION_END(Class)
//! \~\brief
//! \~english Macro to access private section by pointer
//! \~russian Макрос для доступа к частной секции
# define PRIVATE
//! \~\brief
//! \~english Macro to access private section by pointer without brakes ()
//! \~russian Макрос для доступа к частной секции без обрамляющих скобок ()
# define PRIVATEWB
//! \~\brief
//! \~english Macro to start static initializer
//! \~russian Макрос для начала статической инициализации
# define STATIC_INITIALIZER_BEGIN
//! \~\brief
//! \~english Macro to end static initializer
//! \~russian Макрос для окончания статической инициализации
# define STATIC_INITIALIZER_END
//! \~\brief
//! \~english Macro to remove class copy availability
//! \~russian Макрос для запрета копирования класса
# define NO_COPY_CLASS(Class)
//! \~\brief
//! \~english Macro to supress compiler warning about unused variable
//! \~russian Макрос для подавления предупреждения компилятора о неиспользуемой переменной
# define NO_UNUSED(x)
# undef MICRO_PIP
# undef FREERTOS
#endif // DOXYGEN
#ifdef WINDOWS
# ifdef CC_VC
# define SHUT_RDWR 2
# pragma comment(lib, "Ws2_32.lib")
# pragma comment(lib, "Iphlpapi.lib")
# pragma comment(lib, "Psapi.lib")
# ifdef ARCH_BITS_32
# define _X86_
# else
# define _IA64_
# endif
# else
# define SHUT_RDWR SD_BOTH
# endif
typedef int socklen_t;
extern long long __pi_perf_freq;
#endif
#ifndef DOXYGEN
# ifdef ANDROID
// # define tcdrain(fd) ioctl(fd, TCSBRK, 1)
// inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
// inline int mbtowc(wchar_t * w, const char * c, size_t) {*w = ((wchar_t * )&c)[0]; return 1;}
# endif
# ifdef MAC_OS
# define environ (*_NSGetEnviron())
typedef long time_t;
# endif
# ifdef LINUX
# define environ __environ
# endif
# ifdef FREE_BSD
extern char ** environ;
# endif
# ifndef NO_UNUSED
# define NO_UNUSED(x) (void)x
# endif
# ifndef assert
# define assert(x)
# define assertm(exp, msg)
# else
# define assertm(exp, msg) assert(((void)msg, exp))
# endif
# ifdef MICRO_PIP
# define __PIP_TYPENAME__(T) "?"
# else
# define __PIP_TYPENAME__(T) typeid(T).name()
# endif
# ifdef CC_GCC
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED __attribute__((deprecated))
# define DEPRECATEDM(msg) __attribute__((deprecated(msg)))
# if CC_GCC_VERSION > 0x025F // > 2.95
# pragma GCC diagnostic warning "-Wdeprecated-declarations"
# ifdef LINUX
# define HAS_LOCALE
# endif
# ifdef MAC_OS
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# endif
# endif
# ifdef ANDROID
# pragma GCC diagnostic ignored "-Wunused-parameter"
# pragma GCC diagnostic ignored "-Wextra"
# pragma GCC diagnostic ignored "-Wc++11-extensions"
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
// # pragma GCC diagnostic ignored "-Wliteral-suffix"
# endif
# endif
# ifdef CC_VC
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED __declspec(deprecated)
# define DEPRECATEDM(msg) __declspec(deprecated(msg))
# pragma warning(disable: 4018)
# pragma warning(disable: 4061)
# pragma warning(disable: 4100)
# pragma warning(disable: 4239)
# pragma warning(disable: 4242)
# pragma warning(disable: 4244)
# pragma warning(disable: 4251)
# pragma warning(disable: 4365)
# pragma warning(disable: 4512)
# pragma warning(disable: 4668)
# pragma warning(disable: 4710)
# pragma warning(disable: 4800)
# pragma warning(disable: 4820)
# pragma warning(disable: 4986)
# pragma warning(disable: 4996)
# ifdef ARCH_BITS_32
typedef long ssize_t;
# else
typedef long long ssize_t;
# endif
# endif
# ifdef CC_OTHER
# undef DEPRECATED
# undef DEPRECATEDM
# define DEPRECATED
# define DEPRECATEDM(msg)
# endif
#endif // DOXYGEN
// Private data macros
#ifndef DOXYGEN
# define PRIVATE_DECLARATION(e) \
struct __Private__; \
friend struct __Private__; \
struct e __PrivateInitializer__ { \
__PrivateInitializer__(); \
__PrivateInitializer__(const __PrivateInitializer__ & o); \
~__PrivateInitializer__(); \
__PrivateInitializer__ & operator=(const __PrivateInitializer__ & o); \
__Private__ * p = nullptr; \
}; \
__PrivateInitializer__ __privateinitializer__;
# define PRIVATE_DEFINITION_START(c) struct c::__Private__ {
# define PRIVATE_DEFINITION_END(c) \
} \
; \
c::__PrivateInitializer__::__PrivateInitializer__() { \
p = new c::__Private__(); \
} \
c::__PrivateInitializer__::__PrivateInitializer__(const c::__PrivateInitializer__ &) { /*if (p) delete p;*/ \
p = new c::__Private__(); \
} \
c::__PrivateInitializer__::~__PrivateInitializer__() { \
piDeleteSafety(p); \
} \
c::__PrivateInitializer__ & c::__PrivateInitializer__::operator=(const c::__PrivateInitializer__ &) { \
piDeleteSafety(p); \
p = new c::__Private__(); \
return *this; \
}
# define PRIVATE (__privateinitializer__.p)
# define PRIVATEWB __privateinitializer__.p
#endif // DOXYGEN
#define NO_COPY_CLASS(name) \
name(const name &) = delete; \
name & operator=(const name &) = delete;
#define _PIP_ADD_COUNTER_WS(a, cnt, line) a##cnt##_##line
#define _PIP_ADD_COUNTER_WF(a, cnt, line) _PIP_ADD_COUNTER_WS(a, cnt, line)
#define _PIP_ADD_COUNTER(a) _PIP_ADD_COUNTER_WF(a, __COUNTER__, __LINE__)
#define STATIC_INITIALIZER_BEGIN \
class { \
class _Initializer_ { \
public: \
_Initializer_() {
#define STATIC_INITIALIZER_END \
} \
} \
_initializer_; \
} \
_PIP_ADD_COUNTER(_pip_initializer_);
//! \~\brief
//! \~english Minimal sleep in milliseconds for internal PIP using
//! \~russian Минимальное значание задержки в милисекундах для внутреннего использования в библиотеке PIP
//! \~\details
//! \~english Using in \a piMinSleep(), \a PIThread, \a PITimer::Pool. By default 1ms.
//! \~russian Используется в \a piMinSleep(), \a PIThread, \a PITimer::Pool. По умолчанию равна 1мс.
#ifndef PIP_MIN_MSLEEP
# ifndef MICRO_PIP
# define PIP_MIN_MSLEEP 1.
# else
# define PIP_MIN_MSLEEP 10.
# endif
#endif
//! \~\brief
//! \~english Macro used for infinite loop
//! \~russian Макрос для бесконечного цикла
#define FOREVER for (;;)
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define FOREVER_WAIT FOREVER piMinSleep();
//! \~\brief
//! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define WAIT_FOREVER FOREVER piMinSleep();
#endif // PIBASE_MACROS_H

View File

@@ -1,525 +0,0 @@
/*! \file pibinarystream.h
* \ingroup Core
* \~\brief
* \~english Binary serialization interface
* \~russian Интерфейс бинарной сериализации
*/
/*
PIP - Platform Independent Primitives
Binary serialization interface
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBINARYSTREAM_H
#define PIBINARYSTREAM_H
#include "pimemoryblock.h"
#include "pibitarray.h"
#include "pimap.h"
#include "pivector2d.h"
#define PIP_BINARY_STREAM
#define BINARY_STREAM_FRIEND(T) \
template<typename P> friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v); \
template<typename P> friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v);
#define BINARY_STREAM_WRITE(T) \
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v)
#define BINARY_STREAM_READ(T) \
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v)
//! \ingroup Core
//! \~\brief
//! \~english Binary serialization interface.
//! \~russian Интерфейс бинарной сериализации.
//! \~\details
//! \~english In your class you should implement this methods:
//! \~russian В производном классе вы должны реализовать следующие методы:
//! \~\code
//! bool binaryStreamAppendImp (const void * d, size_t s);
//! bool binaryStreamTakeImp (void * d, size_t s);
//! ssize_t binaryStreamSizeImp () const;
//! \endcode
//! \~english Function binaryStreamSizeImp should return -1 if size unknown.
//! \~russian Функция binaryStreamSizeImp должна возвращать -1 если нет информации о размере.
//! \~english See details \ref iostream.
//! \~russian Подробнее \ref iostream.
template<typename P>
class PIBinaryStream {
public:
//! \~russian Записать данные
bool binaryStreamAppend(const void * d, size_t s) {
if (!static_cast<P*>(this)->binaryStreamAppendImp(d, s)) {
return false;
printf("[PIBinaryStream] binaryStreamAppend() error\n");
}
return true;
}
//! \~russian Прочитать данные
bool binaryStreamTake(void * d, size_t s) {
if (!static_cast<P*>(this)->binaryStreamTakeImp(d, s)) {
return false;
printf("[PIBinaryStream] binaryStreamTake() error\n");
}
return true;
}
//! \~russian Узнать оставшийся размер
//!\~\details
//!\~russian Возвращает -1 если нет информации о размере
ssize_t binaryStreamSize() const {
return static_cast<P*>(this)->binaryStreamSizeImp();
}
//! \~russian Записать данные
template<typename T>
void binaryStreamAppend(T v) {binaryStreamAppend(&v, sizeof(v));}
//! \~russian Прочитать int
int binaryStreamTakeInt() {
int r = 0;
binaryStreamTake(&r, sizeof(r));
return r;
}
};
// helper class to detect default operators
template<typename P>
class PIBinaryStreamTrivialRef {
public:
PIBinaryStreamTrivialRef(PIBinaryStream<P> & s): p(s) {}
PIBinaryStream<P> & p;
};
template<typename P, typename T> inline PIBinaryStream<P> & operator <<(PIBinaryStreamTrivialRef<P> s, const T & v) {
s.p << v;
return s.p;
}
template<typename P, typename T> inline PIBinaryStream<P> & operator >>(PIBinaryStreamTrivialRef<P> s, T & v) {
s.p >> v;
return s.p;
}
// specify types
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const bool v) {
s.binaryStreamAppend((uchar)v);
return s;
}
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, bool & v) {
uchar c;
s.binaryStreamTake(&c, sizeof(c));
v = c;
return s;
}
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMemoryBlock v) {
s.binaryStreamAppend(v.data(), v.size());
return s;
}
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMemoryBlock v) {
s.binaryStreamTake(v.data(), v.size());
return s;
}
// store simple types
template<typename P, typename T,
typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v) {
//piCout << "<< enum";
s.binaryStreamAppend((int)v);
return s;
}
template<typename P, typename T,
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStreamTrivialRef<P> operator <<(PIBinaryStream<P> & s, const T & v) {
s.binaryStreamAppend(&v, sizeof(v));
return s;
}
//! \~english Store operator for PIVector of any trivial copyable type
//! \~russian Оператор сохранения для PIVector тривиальных типов
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
//piCout << "<< vector trivial default";
s.binaryStreamAppend((int)v.size());
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
return s;
}
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
//piCout << "<< vector trivial custom";
s.binaryStreamAppend((int)v.size());
for (size_t i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \~english Store operator for PIDeque of any trivial copyable type
//! \~russian Оператор сохранения для PIDeque тривиальных типов
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
//piCout << "<< deque trivial default";
s.binaryStreamAppend((int)v.size());
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
return s;
}
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
//piCout << "<< deque trivial custom";
s.binaryStreamAppend((int)v.size());
for (size_t i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \~english Store operator for PIVector2D of any trivial copyable type
//! \~russian Оператор сохранения для PIVector2D тривиальных типов
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
//piCout << "<< vector2d trivial default";
s.binaryStreamAppend((int)v.rows());
s.binaryStreamAppend((int)v.cols());
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
return s;
}
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
//piCout << "<< vector2d trivial custom";
s.binaryStreamAppend((int)v.rows());
s.binaryStreamAppend((int)v.cols());
s << v.toPlainVector();
return s;
}
//! \~english Store operator
//! \~russian Оператор сохранения
template<typename P>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
//! \~english Store operator
//! \~russian Оператор сохранения
template<typename P, typename Type0, typename Type1>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
// restore simple types
template<typename P, typename T,
typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v) {
//piCout << ">> enum";
v = (T)s.binaryStreamTakeInt();
return s;
}
template<typename P, typename T,
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStreamTrivialRef<P> operator >>(PIBinaryStream<P> & s, T & v) {
if (!s.binaryStreamTake(&v, sizeof(v))) {
printf("error with %s\n", __PIP_TYPENAME__(T));
assert(false);
}
return s;
}
//! \~english Restore operator for PIVector of any trivial copyable type
//! \~russian Оператор извлечения для PIVector тривиальных типов
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
//piCout << ">> vector trivial default";
int sz = s.binaryStreamTakeInt();
v._resizeRaw(sz);
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(false);
}
return s;
}
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
//piCout << ">> vector trivial custom";
int sz = s.binaryStreamTakeInt();
v._resizeRaw(sz);
for (int i = 0; i < sz; ++i) s >> v[i];
return s;
}
//! \~english Restore operator for PIDeque of any trivial copyable type
//! \~russian Оператор извлечения для PIDeque тривиальных типов
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
//piCout << ">> deque trivial default";
int sz = s.binaryStreamTakeInt();
v._resizeRaw(sz);
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(false);
}
return s;
}
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
//piCout << ">> deque trivial custom";
int sz = s.binaryStreamTakeInt();
v._resizeRaw(sz);
for (int i = 0; i < sz; ++i) s >> v[i];
return s;
}
//! \~english Restore operator for PIVector2D of any trivial copyable type
//! \~russian Оператор извлечения для PIVector2D тривиальных типов
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
//piCout << ">> vector2d trivial default";
int r, c;
r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt();
v._resizeRaw(r, c);
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
assert(false);
}
return s;
}
template<typename P, typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
//piCout << ">> vector2d trivial custom";
int r, c;
PIVector<T> tmp;
r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt();
s >> tmp;
v = PIVector2D<T>(r, c, tmp);
return s;
}
//! \~english Restore operator
//! \~russian Оператор извлечения
template<typename P>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIBitArray & v) {s >> v.size_ >> v.data_; return s;}
//! \~english Restore operator
//! \~russian Оператор извлечения
template<typename P, typename Type0, typename Type1>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
// store complex types
//! \~english Store operator for PIVector of any compound type
//! \~russian Оператор сохранения для PIVector сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
//piCout << "<< vector complex";
s.binaryStreamAppend(int(v.size_s()));
for (size_t i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \~english Store operator for PIDeque of any compound type
//! \~russian Оператор сохранения для PIDeque сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
//piCout << "<< deque complex";
s.binaryStreamAppend(int(v.size_s()));
for (size_t i = 0; i < v.size(); ++i) s << v[i];
return s;
}
//! \~english Store operator for PIVector2D of any compound type
//! \~russian Оператор сохранения для PIVector2D сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
//piCout << "<< vector2d complex";
s.binaryStreamAppend(int(v.rows()));
s.binaryStreamAppend(int(v.cols()));
s << v.toPlainVector();
return s;
}
// restore complex types
//! \~english Restore operator for PIVector of any compound type
//! \~russian Оператор извлечения для PIVector сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
//piCout << ">> vector complex";
/*if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}*/
v.resize(s.binaryStreamTakeInt());
for (size_t i = 0; i < v.size(); ++i) s >> v[i];
return s;
}
//! \~english Restore operator for PIDeque of any compound type
//! \~russian Оператор извлечения для PIDeque сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
//piCout << ">> deque complex";
/*if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}*/
v.resize(s.binaryStreamTakeInt());
for (size_t i = 0; i < v.size(); ++i) s >> v[i];
return s;
}
//! \~english Restore operator for PIVector2D of any compound type
//! \~russian Оператор извлечения для PIVector2D сложных типов
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
//piCout << ">> vector2d complex";
/*if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}*/
int r, c;
PIVector<T> tmp;
r = s.binaryStreamTakeInt();
c = s.binaryStreamTakeInt();
s >> tmp;
v = PIVector2D<T>(r, c, tmp);
return s;
}
// other types
//! \~english Store operator
//! \~russian Оператор сохранения
template <typename P, typename Key, typename T>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMap<Key, T> & v) {
s.binaryStreamAppend((int)v.pim_index.size_s());
for (uint i = 0; i < v.size(); ++i) {
s.binaryStreamAppend((int)v.pim_index[i].index);
s << v.pim_index[i].key;
}
s << v.pim_content;
return s;
}
//! \~english Restore operator
//! \~russian Оператор извлечения
template <typename P, typename Key, typename T>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
/*if (s.size_s() < 4) {
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}*/
int sz = s.binaryStreamTakeInt(); v.pim_index.resize(sz);
int ind = 0;
for (int i = 0; i < sz; ++i) {
ind = s.binaryStreamTakeInt();
s >> v.pim_index[i].key;
v.pim_index[i].index = ind;
}
s >> v.pim_content;
if (v.pim_content.size_s() != v.pim_index.size_s()) {
piCout << "Warning: loaded invalid PIMap, clear";
v.clear();
}
return s;
}
// non-defined complex types
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & ) {
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator << for complex type!");
return s;
}
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & ) {
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator >> for complex type!");
return s;
}
#endif

View File

@@ -1,116 +0,0 @@
/*! \file pibitarray.h
* \~\brief
* \~english Bit array
* \~russian Битовый массив
*/
/*
PIP - Platform Independent Primitives
Bit array
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PIBITARRAY_H
#define PIBITARRAY_H
#include "pivector.h"
class PIP_EXPORT PIBitArray {
template <typename P>
friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIBitArray & v);
template <typename P>
friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIBitArray & v);
public:
PIBitArray(const int & size = 0) {resize(size);}
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
PIBitArray(ushort val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(uint val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(ulong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(ullong val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
PIBitArray(const uchar * bytes, uint size) {resize(size * 8); memcpy(data(), bytes, size);}
uint bitSize() const {return size_;}
uint byteSize() const {return bytesInBits(size_);}
PIBitArray & resize(const uint & size) {size_ = size; data_.resize(bytesInBits(size_)); return *this;}
PIBitArray & clearBit(const uint & index) {data_[index / 8] &= ~(1 << (index % 8)); return *this;}
PIBitArray & setBit(const uint & index) {data_[index / 8] |= (1 << (index % 8)); return *this;}
PIBitArray & writeBit(const uint & index, const bool & value) {if (value) setBit(index); else clearBit(index); return *this;}
PIBitArray & writeBit(const uint & index, const uchar & value) {return writeBit(index, value > 0);}
PIBitArray & push_back(const bool & value) {resize(size_ + 1); writeBit(size_ - 1, value); return *this;}
PIBitArray & push_back(const uchar & value) {return push_back(value > 0);}
PIBitArray & insert(const uint & index, const bool & value) {
resize(size_ + 1);
uint fi = byteSize() - 1, si = index / 8, ti = index % 8;
uchar c = data_[si];
for (uint i = fi; i > si; --i) {
data_[i] <<= 1;
if ((0x80 & data_[i - 1]) == 0x80) data_[i] |= 1;
else data_[i] &= 0xFE;}
data_[si] &= (0xFF >> (7 - ti));
data_[si] |= ((c << 1) & (0xFF << (ti)));
if (value) data_[si] |= (1 << ti);
else data_[si] &= ~(1 << ti);
return *this;}
PIBitArray & insert(const uint & index, const uchar & value) {return insert(index, value > 0);}
PIBitArray & push_front(const bool & value) {return insert(0, value);}
PIBitArray & push_front(const uchar & value) {return push_front(value > 0);}
PIBitArray & pop_back() {return resize(size_ - 1);}
PIBitArray & pop_front() {
if (size_ == 0) return *this;
uint fi = byteSize() - 1;
for (uint i = 0; i < fi; ++i) {
data_[i] >>= 1;
if ((1 & data_[i + 1]) == 1) data_[i] |= 0x80;
else data_[i] &= 0x7F;}
data_[fi] >>= 1;
resize(size_ - 1);
return *this;}
PIBitArray & append(const PIBitArray & ba) {for (uint i = 0; i < ba.bitSize(); ++i) push_back(ba[i]); return *this;}
uchar * data() {return data_.data();}
uchar toUChar() {if (size_ == 0) return 0; return data_[0];}
ushort toUShort() {ushort t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
uint toUInt() {uint t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
ulong toULong() {ulong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
ullong toULLong() {ullong t = 0; memcpy(&t, data(), piMin<uint>(byteSize(), sizeof(t))); return t;}
bool at(const uint & index) const {return (1 & (data_[index / 8] >> (index % 8))) == 1 ? true : false;}
bool operator [](const uint & index) const {return at(index);}
void operator +=(const PIBitArray & ba) {append(ba);}
bool operator ==(const PIBitArray & ba) const {if (bitSize() != ba.bitSize()) return false; for (uint i = 0; i < bitSize(); ++i) if (at(i) != ba[i]) return false; return true;}
bool operator !=(const PIBitArray & ba) const {return !(*this == ba);}
void operator =(const uchar & val) {resize(sizeof(val) * 8); data_[0] = val;}
void operator =(const ushort & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const uint & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const ulong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
void operator =(const ullong & val) {resize(sizeof(val) * 8); memcpy(data(), &val, sizeof(val));}
private:
static uint bytesInBits(const uint & bits) {return (bits + 7) / 8;}
PIVector<uchar> data_;
uint size_;
};
#ifdef PIP_STD_IOSTREAM
//std::ostream & operator <<(std::ostream & s, const PIBitArray & ba);
#endif
PICout operator <<(PICout s, const PIBitArray & ba);
#endif // PIBITARRAY_H

View File

@@ -1,130 +0,0 @@
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "picli.h"
#include "pisysteminfo.h"
//! \class PICLI picli.h
//! \details
//! \~english \section PICLI_sec0 Synopsis
//! \~russian \section PICLI_sec0 Краткий обзор
//! \~english
//! This class provide handy parsing of command-line arguments. First you should add
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
//! is some argument in application command-line with function \a hasArgument(),
//! or obtain argument value by \a argumentValue().
//!
//! \~russian
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
//! а также получить их значения при помощи \a argumentValue().
//!
//! \~english \section PICLI_sec1 Example
//! \~russian \section PICLI_sec1 Пример
//! \~\code
//! int main(int argc, char ** argv) {
//! PICLI cli(argc, argv);
//! cli.addArgument("console");
//! cli.addArgument("debug");
//! cli.addArgument("Value", "v", "value", true);
//! if (cli.hasArgument("console"))
//! piCout << "console active";
//! if (cli.hasArgument("debug"))
//! piCout << "debug active";
//! piCout << "Value =" << cli.argumentValue("Value");
//! return 0;
//! }
//!
//! These executions are similar:
//! a.out -cd -v 10
//! a.out --value 10 -dc
//! a.out -c -v 10 -d
//! a.out --console -d -v 10
//! a.out --debug -c --value 10
//! \endcode
//!
PICLI::PICLI(int argc, char * argv[]) {
needParse = debug_ = true;
_prefix_short = "-";
_prefix_full = "--";
_count_opt = 0;
_count_mand = 0;
for (int i = 0; i < argc; ++i)
_args_raw << argv[i];
if (argc > 0)
PISystemInfo::instance()->execCommand = argv[0];
}
void PICLI::parse() {
if (!needParse) return;
PIString cra, full;
Argument * last = 0;
for (int i = 1; i < _args_raw.size_s(); ++i) {
cra = _args_raw[i];
if (cra.left(2) == _prefix_full) {
last = 0;
full = cra.right(cra.length() - 2);
piForeach (Argument & a, _args) {
if (a.full_key == full) {
a.found = true;
last = &a;
break;
}
}
} else {
if (cra.left(1) == _prefix_short) {
last = 0;
for (int j = 1; j < cra.length(); ++j) {
bool found = false;
piForeach (Argument & a, _args) {
if ((a.short_key != '\0') && (a.short_key == cra[j])) {
a.found = true;
last = &a;
found = true;
break;
}
}
if (!found) break;
}
} else {
if (last == 0 ? true : !last->has_value) {
if (_args_mand.size_s() < _count_mand) {
_args_mand << cra;
continue;
}
if (_args_opt.size_s() < _count_opt || _count_opt < 0) {
_args_opt << cra;
continue;
}
piCoutObj << "[PICli] Arguments overflow, \"" << cra << "\" ignored";
}
if (last == 0 ? false : last->has_value) {
last->value = cra;
last = 0;
}
}
}
}
needParse = false;
}

View File

@@ -1,128 +0,0 @@
/*! \file picli.h
* \ingroup Core
* \~\brief
* \~english Command-Line parser
* \~russian Парсер командной строки
*/
/*
PIP - Platform Independent Primitives
Command-Line Parser
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PICLI_H
#define PICLI_H
#include "pistringlist.h"
#include "piset.h"
//! \ingroup Core
//! \~\brief
//! \~english Command-Line parser.
//! \~russian Парсер командной строки.
class PIP_EXPORT PICLI
{
public:
//! \~english Constructor
//! \~russian Конструктор
PICLI(int argc, char * argv[]);
//! \~english Add argument with name "name", short key = name first letter and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени
void addArgument(const PIString & name, bool value = false) {_args << Argument(name, name[0], name, value); needParse = true;}
//! \~english Add argument with name "name", short key = "shortKey" and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {_args << Argument(name, shortKey, name, value); needParse = true;}
//! \~english Add argument with name "name", short key = "shortKey" and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени
void addArgument(const PIString & name, const char * shortKey, bool value = false) {_args << Argument(name, PIChar(shortKey), name, value); needParse = true;}
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey"
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey"
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, shortKey, fullKey, value); needParse = true;}
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey"
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey"
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, PIChar(shortKey), fullKey, value); needParse = true;}
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы
PIString rawArgument(int index) {parse(); return _args_raw[index];}
PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
PIString optionalArgument(int index) {parse(); return _args_opt[index];}
//! \~english Returns unparsed command-line arguments
//! \~russian Возвращает исходные аргументы командной строки
const PIStringList & rawArguments() {parse(); return _args_raw;}
const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
const PIStringList & optionalArguments() {parse(); return _args_opt;}
//! \~english Returns program execute command without arguments
//! \~russian Возвращает команду вызова программы без аргументов
PIString programCommand() {parse(); return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
//! \~english Returns if argument "name" found
//! \~russian Возвращает найден ли аргумент "name"
bool hasArgument(const PIString & name) {parse(); piForeach (Argument & i, _args) if (i.name == name && i.found) return true; return false;}
//! \~english Returns argument "name" value, or empty string if this is no value
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет
PIString argumentValue(const PIString & name) {parse(); piForeach (Argument &i, _args) if (i.name == name && i.found) return i.value; return PIString();}
PIString argumentShortKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.short_key; return PIString();}
PIString argumentFullKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.full_key; return PIString();}
const PIString & shortKeyPrefix() const {return _prefix_short;}
const PIString & fullKeyPrefix() const {return _prefix_full;}
int mandatoryArgumentsCount() const {return _count_mand;}
int optionalArgumentsCount() const {return _count_opt;}
void setShortKeyPrefix(const PIString & prefix) {_prefix_short = prefix; needParse = true;}
void setFullKeyPrefix(const PIString & prefix) {_prefix_full = prefix; needParse = true;}
void setMandatoryArgumentsCount(const int count) {_count_mand = count; needParse = true;}
void setOptionalArgumentsCount(const int count) {_count_opt = count; needParse = true;}
bool debug() const {return debug_;}
void setDebug(bool debug) {debug_ = debug;}
PIConstChars className() const {return "PICLI";}
PIString name() const {return PIStringAscii("CLI");}
private:
struct Argument {
Argument() {has_value = found = false;}
Argument(const PIString & n, const PIChar & s, const PIString & f, bool v) {name = n; short_key = s; full_key = f; has_value = v; found = false;}
PIString name;
PIChar short_key;
PIString full_key;
PIString value;
bool has_value, found;
};
void parse();
PIString _prefix_short, _prefix_full;
PIStringList _args_raw, _args_mand, _args_opt;
PISet<PIString> keys_full, keys_short;
PIVector<Argument> _args;
int _count_mand, _count_opt;
bool needParse, debug_;
};
#endif // PICLI_H

Some files were not shown because too many files have changed in this diff Show More