577 Commits

Author SHA1 Message Date
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
8551499a5e PICout refactoring, new SHSTKMacros 2022-08-07 22:07:26 +03:00
Бычков Андрей
1eaecb288f PIMapIterators refactoring
PIChunkStream some refactoring
2022-08-05 17:05:56 +03:00
Бычков Андрей
170a713357 PIMap new functions
PIByteArray checksum crc
some doc fixes
2022-08-04 20:20:08 +03:00
54cc6c55b2 pip_cmg and picodeinfo.h doc 2022-08-03 14:14:24 +03:00
e6aa3c34d4 Merge pull request 'added and fixed documentation for PIMath' (#101) from math-doc into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/101
2022-08-03 08:49:08 +03:00
bb40f69298 doc clean 2022-08-03 08:47:25 +03:00
af9a9e78b9 doc 2022-08-02 17:08:51 +03:00
af1264e42b doc fix 2022-08-02 08:25:34 +03:00
eb91fbfc45 doc stream 2022-08-01 21:23:21 +03:00
4ea5465637 PIString:: mid and cutMid does nothing if "start" < 0 2022-08-01 19:29:40 +03:00
ab7769dd5a map and set fix 2022-08-01 19:07:23 +03:00
b1e220e454 change PIIODevice read* and write* methods size to "ssize_t" 2022-08-01 18:52:30 +03:00
1b499530c5 add pisd deploy 2022-08-01 18:20:58 +03:00
b0d48caaad version 2.98.0
remove PIFile::readLine()
partially migrate PIConfig to text stream
add more "override"
2022-08-01 18:13:22 +03:00
Tamerlan Baziev
d6758a8562 исправление ошибок в документации 2022-08-01 12:29:42 +03:00
97734953dd PIString(int) constructors delete 2022-07-29 22:25:21 +03:00
bd98583116 PIString delete operator += int
PICout fix
2022-07-29 20:09:40 +03:00
Бычков Андрей
ddba8f401b PICout fix 2022-07-29 18:16:42 +03:00
Бычков Андрей
4725eb96d6 replace typedef function ptr by std::function
start PIMap refactoring
2022-07-29 15:49:36 +03:00
Бычков Андрей
38fd1b5dc4 PIPacketExtractor теперь работает 2022-07-28 17:02:33 +03:00
16c12a2756 Merge pull request 'Много исправлений и добавлений' (#100) from pip297 into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/100
2022-07-28 14:47:24 +03:00
Бычков Андрей
1b09ad5c27 binlog fixes
PIBinaryStream doc
remove makePIPair
rename bytesAvailable
2022-07-28 14:46:58 +03:00
Бычков Андрей
00d06f71ba version 2022-07-27 15:46:53 +03:00
Бычков Андрей
3873f0b03b PIIODevice::bytesAvailible()
fix pistringlist pibinarystream write
pibinarystream::binaryStreamSize()
PIByteArray pibinarystream read with more size fix
pistring pibinarystream read optimization
fix bug in PIIOBinaryStream read and write if failed
workaround in PIIOString::readDevice
PISPI readDevice bug Fixed
2022-07-27 15:43:04 +03:00
6ae6e9a540 remove test 2022-07-27 10:11:55 +03:00
Tamerlan Baziev
bbc83128b0 added and fixed documentation for PIMath
- added documentation for PIPoint, PILine;
- fixed documentation for PIMathMatrix.
2022-07-26 18:13:28 +03:00
Бычков Андрей
d13e68c206 threadedRead now const uchar *
pipacketextractor Header mode now more flexible
fix splitTime mode
more refactoring
add virtual override to functions
remove piforeach
replace 0 to nullptr
iterate over pimap via iterators
replace CONNECTU to CONNECT# with compile time check
2022-07-26 17:18:08 +03:00
a4882dc054 complex macros with ; 2022-07-25 11:18:09 +03:00
Бычков Андрей
a1b9b7e1d6 убрал лишние ; 2022-07-25 10:32:42 +03:00
Бычков Андрей
e1b89aeca8 PIByteArray begin end indexOf map reduce forEach
PIVector and PIDeque small fixes
2022-07-25 10:07:48 +03:00
242abaaf59 version 2.95.0
get rid of PIByteArray subclassing from PIDeque<uchar>
2022-07-22 16:40:09 +03:00
Бычков Андрей
0116387fe3 PIDeque fix ssize_t
fix uninitialized variables
fix PIDeque prepend with std::initializer_list
2022-07-22 16:31:40 +03:00
Бычков Андрей
f5953a0ba7 PIBinaryLog joinBinLogsSerial
correct timestamp wite with split
2022-07-22 15:24:07 +03:00
Бычков Андрей
7aa407264f Merge remote-tracking branch 'remotes/origin/stream_interface'
PIBinaryLog
2022-07-22 15:22:33 +03:00
Бычков Андрей
59c7896577 Merge branch 'pip2' 2022-07-22 11:18:03 +03:00
Бычков Андрей
a69de63db0 PISerial windows custom speed 2022-07-20 15:41:47 +03:00
e96b399da7 pip_cmg fix 2022-06-24 16:43:22 +03:00
33eefd7453 pip_cmg namespace fix 2022-06-24 14:46:55 +03:00
c7fffe1280 PIBinaryLog miss 2022-06-24 12:19:03 +03:00
1b04d7ecce version 2.93 ready to master
remove PIString << operators
2022-06-24 12:10:57 +03:00
b66272a68a version 2.92
pip_cmg
2022-06-09 17:59:04 +03:00
12c032392c pip_cmg namespaces fix 2022-05-20 15:23:01 +03:00
ffa25c18f0 pip_cmg include fix 2022-05-15 17:56:52 +03:00
f67e3030b9 move to PIIOTextStream 2022-05-13 13:24:09 +03:00
1028233553 version 2.91.0, PITextStream works 2022-05-13 11:26:01 +03:00
ef8ffcd02f DEPRECATED[M], createMemoryBlock(), text stream ... 2022-05-11 20:55:51 +03:00
0897a8369f macros rename 2022-05-11 16:49:33 +03:00
fa19ad1093 text stream ... 2022-05-11 12:39:36 +03:00
8c6b3613b6 code brush 2022-05-11 10:48:36 +03:00
a23eb341e2 pitextstream starts 2022-05-10 18:47:11 +03:00
b2bc385397 PIByteArray works on binary stream 2022-05-10 15:23:18 +03:00
0f9e592273 start moving to binarystream 2022-05-10 12:26:05 +03:00
cf4f58ed95 ready to integrate 2022-05-09 23:57:47 +03:00
0243f588bc before error detection 2022-05-09 22:35:53 +03:00
af77974e91 first try 2022-05-09 14:21:38 +03:00
a502182eba NO_UNUSED 2022-05-09 11:56:09 +03:00
d219baee27 path fix 2022-05-08 22:29:35 +03:00
0ea1e2c856 support for git download of CMake project (standalone PIP build) 2022-05-08 22:22:48 +03:00
3107949e6f doc, small fixes 2022-05-08 19:23:52 +03:00
460519c075 PISingleApplication fix and optimize 2022-05-08 16:35:01 +03:00
9347ed2e55 doc 2022-05-06 23:42:20 +03:00
5770adfd34 PIMap fix 2022-05-06 16:27:40 +03:00
9714d8ea42 PIMap {{K, T}, {K, T}, ...} constructor
doc ru
2022-05-06 12:45:08 +03:00
0b3ee4bb6a doc ru 2022-05-05 22:31:59 +03:00
d1f7065c8a PICout::writePIString -> PICout::write 2022-05-05 10:35:15 +03:00
6995c25613 PIIODevice fullPathPrefix returns PIConstChars 2022-05-04 16:33:05 +03:00
28ce6e8f3f version 2.39.0
PIString works with PIConstChars
picodeinfo optimizations
PIIODevice::availableClasses
2022-05-03 18:44:00 +03:00
8d5730f715 PIPluginLoader +1 error 2022-04-30 16:07:30 +03:00
2bbdbc3ac9 PIIODevice registration dramatically optimization 2022-04-30 11:21:57 +03:00
19e4eee222 PIConstChars API 2022-04-30 09:05:14 +03:00
4139d88103 PIConstChars PIMap supports 2022-04-30 00:07:58 +03:00
6881fd13b7 PIConstChars 2022-04-29 23:53:07 +03:00
Andrey
8c8553a6af PIObject Property const char * 2022-04-29 18:17:03 +03:00
97dd19f0c7 !!!!!!!!!!!!!!!!!! 2022-04-27 16:34:12 +03:00
Andrey
784c949b1a Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-27 15:49:37 +03:00
Andrey
7325e12e30 PIString doc 2022-04-27 15:49:30 +03:00
019ddbb80b TileInput fix 2022-04-27 13:35:27 +03:00
Andrey
6322b248a8 dtos fix 2022-04-27 13:27:58 +03:00
c1c47b4869 locale changes, piscreen 2022-04-27 12:41:38 +03:00
2f4e73ef13 console encoding patch 2022-04-26 22:49:31 +03:00
5ae1cfae87 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-26 21:02:07 +03:00
5d82caf889 Merge pull request 'PIString wo pideue parent' (#91) from pistring_unparent into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/91
2022-04-26 21:01:36 +03:00
d3028a3ce8 pistring remove indexOf* 2022-04-26 21:01:20 +03:00
eef4573a68 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-26 20:04:10 +03:00
48f3b62540 deploy_tool/main.cpp 2022-04-26 20:04:05 +03:00
Andrey
f7d6302572 fix 2022-04-26 17:20:07 +03:00
Andrey
7ad520a1c3 PIString optimization 2022-04-26 17:19:05 +03:00
Andrey
4bc12989ca Merge branch 'master' of https://git.shs.tools/SHS/pip into pistring_unparent 2022-04-26 16:59:36 +03:00
Andrey
186c71d973 linux mb test 2022-04-26 16:41:04 +03:00
Andrey
06c8e6af10 linux mb test 2022-04-26 16:30:26 +03:00
Andrey
69b9589e84 linux mb test 2022-04-26 16:03:37 +03:00
Andrey
5c767c5e3e linux mb test 2022-04-26 16:01:14 +03:00
Andrey
9cd0389a0b PIString wo pideue parent 2022-04-26 14:41:12 +03:00
Andrey
a7ffc85404 piminsleep bug and PIIODevice splitFullPath optimization 2022-04-26 14:09:59 +03:00
Andrey
2e9c3a1dbf PIString benchmarks 2022-04-26 11:53:28 +03:00
9f581335d3 version 2.37 2022-04-26 00:33:17 +03:00
e70e1c0203 pichar fix 2022-04-26 00:17:53 +03:00
cb179de856 linux PIString fix 2022-04-26 00:11:27 +03:00
0aaa5ba890 linux PIString fix 2022-04-25 23:58:38 +03:00
0cf7fb9f25 linux PIString fix 2022-04-25 23:58:06 +03:00
a304997177 linux PIString fix 2022-04-25 23:56:57 +03:00
d6ba51e4bc linux PIString fix 2022-04-25 23:44:30 +03:00
892edb7d5b linux PIString fix 2022-04-25 23:42:46 +03:00
c3cf0f3586 linux PIString fix 2022-04-25 23:41:43 +03:00
2dec17e871 linux PIString fix 2022-04-25 23:41:21 +03:00
88ffd602d6 linux PIString fix 2022-04-25 23:40:17 +03:00
a57e51bdf8 linux PIString fix 2022-04-25 23:39:33 +03:00
44c52c40f1 linux PIString fix 2022-04-25 23:38:09 +03:00
6ecd04b0d8 linux PIString fix 2022-04-25 23:37:06 +03:00
964823b332 linux PIString fix 2022-04-25 23:35:54 +03:00
ca8839f097 linux PIString fix 2022-04-25 23:34:16 +03:00
546ad6a744 linux PIString fix 2022-04-25 23:32:21 +03:00
bd9ad16074 linux PIString fix 2022-04-25 23:31:46 +03:00
23907c7043 fix appendFromChars 2022-04-25 23:06:49 +03:00
a6cea11911 PIString ICU 2022-04-25 22:54:46 +03:00
cea7a7c121 piChar mbrtowc 2022-04-25 22:15:58 +03:00
095ecd254f piChar mbrtowc 2022-04-25 22:14:42 +03:00
2246b8b5fd linux test 2022-04-25 22:01:50 +03:00
914ff5355d Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-25 21:55:14 +03:00
858269a46b linux test 2022-04-25 21:55:10 +03:00
5072d8c915 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-25 21:44:30 +03:00
5f8c04a78e containers minimum elements, windows memory leaks 2022-04-25 21:43:57 +03:00
41fb7cc40d linux fix 2022-04-25 21:32:35 +03:00
6a399c7d39 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-25 20:40:34 +03:00
90afc369f0 string brush 2022-04-25 15:29:27 +03:00
Andrey
765ef7368e PIString replace pibytearray by char * 2022-04-25 11:42:58 +03:00
03384d02a0 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-24 22:11:16 +03:00
cf48c9ebf7 string ascii 2022-04-24 19:15:51 +03:00
dd3d42944e Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-23 13:59:23 +03:00
c2e44dc3ba doc fix 2022-04-23 13:59:06 +03:00
c1c324a5a8 doc 2022-04-23 12:44:09 +03:00
7f93ba55b4 doc 2022-04-23 12:37:55 +03:00
fcd871c0fc doc 2022-04-23 12:32:17 +03:00
0c54709414 doc ru 2022-04-23 11:27:07 +03:00
7a458c5cbe doc ru 2022-04-23 00:44:52 +03:00
8da0469dbf Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-22 23:24:34 +03:00
38b75c85d7 doc fix 2022-04-22 23:24:28 +03:00
833d0333d7 doc fixes 2022-04-22 22:28:43 +03:00
e67a426ff2 doc fix 2022-04-22 21:48:35 +03:00
39e4d9a73c doc ru 2022-04-22 21:19:12 +03:00
Andrey
91216c4b17 PIPair doc 2022-04-22 19:20:50 +03:00
Andrey
416b142889 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-22 18:45:04 +03:00
Andrey
cb4df7dc42 fix PIVector and PIDeque typedefs 2022-04-22 18:44:58 +03:00
Andrey
99a4546775 ещё правки для PIVector и PIDeque iterator и убрал лишние строки 2022-04-22 17:54:08 +03:00
Andrey
8a9864a91c PIPair refactoring 2022-04-22 17:35:29 +03:00
6485d81025 piobject metasystem memory and performance optimization 2022-04-22 15:35:25 +03:00
Andrey
db54d0b052 mistake 2022-04-22 12:13:43 +03:00
Andrey
87105cff21 ещё правки документации для PIVector и PIDeque 2022-04-22 12:12:26 +03:00
Andrey
a489daa475 уменьшил количество строк 2022-04-22 11:51:19 +03:00
c476a06e8c containers doc brush 2022-04-21 22:58:24 +03:00
9deae168a6 thread doc ru 2022-04-21 22:26:49 +03:00
Andrey
93b881da1b PIDeque doc, fixes in PIVector and PIString 2022-04-21 18:25:44 +03:00
Andrey
8beaac5193 finish PIVector doc 2022-04-20 16:50:36 +03:00
Andrey
d4294e3d95 PIVector reshape... not works 2022-04-19 16:33:13 +03:00
Andrey
8c6db321cf PIDeque doc 2022-04-18 19:10:01 +03:00
Andrey
35e68bcd0e Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-18 18:16:38 +03:00
Andrey
f01ca5e5bf pivector doc 2022-04-18 18:16:26 +03:00
bef0ac1194 pip_cmg -H 2022-04-16 01:13:10 +03:00
9fa78a1dbf doc 2022-04-15 16:36:14 +03:00
4b32101de6 introspection major optimization 2022-04-15 01:31:22 +03:00
Andrey
6abec38856 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-14 18:00:39 +03:00
Andrey
d22af96bea PIDeque optimization 2022-04-14 18:00:33 +03:00
7b65a59a6e Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-14 17:48:22 +03:00
42e253adc7 PIIntrospection 2022-04-14 17:48:15 +03:00
Andrey
bb45a60d94 Iterators ssize_t 2022-04-14 17:43:55 +03:00
Andrey
fa93c8a486 PIVector doc, forEach refactory 2022-04-14 15:58:40 +03:00
77e0423375 fix pievaluator and PIDeque sort 2022-04-13 23:29:40 +03:00
c7e67b309e picout fix 2022-04-13 22:46:53 +03:00
Andrey
2ab2614ab4 PICout optimization 2022-04-13 17:59:24 +03:00
Andrey
5ed900c46c PIVector doc 2022-04-13 14:50:09 +03:00
Andrey
fb104a9f24 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-04-13 14:02:38 +03:00
Andrey
42bfe7c587 PIVector doc 2022-04-13 14:02:31 +03:00
4f2218619c version, debug printf 2022-04-13 12:31:11 +03:00
Andrey
e4e16764f3 PIP_DEBUG, PIVector sort and doc 2022-04-13 11:22:27 +03:00
00830958df doc ru, printf() before assert in containers 2022-04-12 23:17:05 +03:00
Andrey
486fdf3dcd PIVector doc 2022-04-12 10:43:07 +03:00
Andrey
7cd824f3ab PIVector doc 2022-04-11 17:57:23 +03:00
Andrey
60c9d60079 PIVector reverse_iterator sort 2022-04-07 18:17:23 +03:00
397d273802 support for std::sort in PIVector 2022-04-06 20:48:20 +03:00
a117844233 include fix 2022-04-06 20:22:00 +03:00
d5c27b1181 doc groups 2022-04-06 20:11:47 +03:00
c90d06871e PIVector iterator operators 2022-04-06 08:40:25 +03:00
fb282d405d string doc 2022-04-04 16:17:23 +03:00
Andrey
f83d08cf56 PIVector doc 2022-04-01 18:11:52 +03:00
Andrey
0194e3f6b6 PIVector doc 2022-03-31 17:49:18 +03:00
Andrey
1edd9e4c55 PIVector doc 2022-03-31 17:27:36 +03:00
Andrey
aa417be1d3 PIVector reverse, filter and reversed functions
PIVector lastIndexOf and lastIndexWhere correct behaviour
PIVector doc
picontainersmodule.h doc
2022-03-31 16:32:41 +03:00
Andrey
7ab16b641d PIVector doc 2022-03-31 13:28:18 +03:00
Andrey
42fd417e34 picontainers doc, PIVector doc 2022-03-30 17:32:34 +03:00
Andrey
c2ceb710c5 PIVector doc 2022-03-29 17:30:58 +03:00
Andrey
288062cfd6 Merge branch 'master' of https://git.shs.tools/SHS/pip 2022-03-29 12:39:49 +03:00
Andrey
9f1ae76d1e PIVector doc 2022-03-29 12:39:37 +03:00
7c927da979 Doxyfile.in 2022-03-29 11:59:54 +03:00
Andrey
7a9c3f72ca PIVector doc 2022-03-28 17:59:09 +03:00
35d340aaab doc ru 2022-03-26 21:47:57 +03:00
5d98a7dd3a README.md 2022-03-25 18:09:13 +03:00
5393225538 README.md 2022-03-25 18:08:31 +03:00
831f202536 README.md 2022-03-25 17:54:51 +03:00
81b749caa2 doc, pitime.h decomposition 2022-03-25 17:47:41 +03:00
a50953ae7c Merge pull request 'doxygen-ru' (#87) from doxygen-ru into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/87
2022-03-25 15:58:22 +03:00
08c5d15e6a doc ru 2022-03-25 15:57:40 +03:00
ff70bf6a0e Merge branch 'doxygen-ru' of https://git.shs.tools/SHS/pip into doxygen-ru 2022-03-25 15:45:26 +03:00
a315f7af25 doc pitime.h 2022-03-25 15:45:05 +03:00
Andrey
4c7df57e66 PIString and PIChar fixes 4 2022-03-25 15:10:29 +03:00
Andrey
7dee8f6313 PIString and PIChar fixes 3 2022-03-25 14:10:38 +03:00
Andrey
0ad6ca6602 PIString and PIChar fixes 2 2022-03-25 14:07:37 +03:00
Andrey
649850a1ba PIString and PIChar fixes 2022-03-25 13:49:32 +03:00
Andrey
8bb1af8d2a fix PIChar 2022-03-25 12:35:02 +03:00
7a0adf5e28 Merge pull request 'translation for russian starts' (#85) from doxygen-ru into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/85
2022-03-25 12:12:36 +03:00
Andrey
6241795b60 Merge branch 'master' of https://git.shs.tools/SHS/pip into doxygen-ru
# Conflicts:
#	libs/main/core/pivariant.cpp
#	libs/main/math/pigeometry.h
#	libs/main/math/pimathbase.h
2022-03-25 12:12:15 +03:00
Andrey
9d0451455a README.md ссылки на доку 2022-03-25 12:08:04 +03:00
peri4
9a8b9c7141 doc ru 2022-03-21 22:03:47 +03:00
866f71edb5 Merge pull request 'geometry_refact' (#86) from geometry_refact into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/86
2022-03-21 14:14:12 +03:00
Andrey
4bae04feec code style 2022-03-21 12:20:11 +03:00
Andrey
415160387b PILine 2022-03-21 10:49:41 +03:00
Andrey
3dd0d0b6cf PIRect complete 2022-03-21 10:35:34 +03:00
Andrey
2596b119ac start refactoring pigeometry.h 2022-03-18 18:06:40 +03:00
20e0771331 doc ru 2022-03-18 01:28:07 +03:00
7a26ae7292 doc ru 2022-03-17 18:13:02 +03:00
cc4e1f48aa doc ru 2022-03-17 00:57:15 +03:00
Andrey
6e6305d2ec start PIVector doc 2022-03-16 16:38:09 +03:00
Andrey
3e9cb2481c doc link to ru.cppreference.com for russian doc 2022-03-15 15:40:21 +03:00
Andrey
ea624f1223 picontainers.h doc 2022-03-15 15:34:45 +03:00
Andrey
e4aec3f95e Doxyfile.in upgrade 2022-03-15 15:10:59 +03:00
7d83c6fe19 PIByteArray doc 2022-03-14 23:19:46 +03:00
7ef4321a3d supports for doc language select with cmake 2022-03-14 21:53:30 +03:00
54b5372356 doxygen @ tags replaced to \ 2022-03-14 21:19:31 +03:00
Andrey
9bf1a11701 picontainers.h doxygen fixes, generating html/pip.cfg 2022-03-14 18:17:16 +03:00
Andrey
99280a40ef picontainers.h doxygen partial 2022-03-14 17:14:29 +03:00
Andrey
99061f6e24 utf-8 2022-03-14 12:46:13 +03:00
Andrey
2fd139b1e3 Merge branch 'master' of https://git.shs.tools/SHS/pip into doxygen-ru 2022-03-14 12:31:51 +03:00
ae29b4514c translation for russian starts 2022-03-14 12:11:46 +03:00
58de1ceafc Merge pull request 'micro' (#83) from micro into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/83
2022-03-14 12:10:32 +03:00
20e6d1be99 Merge branch 'master' into micro 2022-03-14 11:57:06 +03:00
2a877fbb6b pip_cmg supports for "simple-stream" PIMETA tag for structs and classes for simple de/serialization without PIChunkStream 2022-03-11 14:39:08 +03:00
2a6ebc9d8d piCompare change position 2022-02-14 19:12:41 +03:00
Andrey
c3c98b9d78 include fixes 2022-02-14 14:01:54 +03:00
Andrey
443e8b46a6 Merge branch 'master' of https://git.shs.tools/SHS/pip into micro 2022-02-11 12:00:49 +03:00
Andrey
fff2aa468a PIP_FORCE_NO_PIINTROSPECTION 2022-02-11 12:00:34 +03:00
1918e55a97 piCompare use piAbs 2022-02-08 00:33:12 +03:00
eb6d378de2 deploy tool unchained from "grep" and support qt6 2022-01-31 19:55:23 +03:00
b1b174ba64 missed include 2022-01-23 12:59:13 +03:00
Andrey
4921a3b0fd arduino PISystemTime::current 2022-01-21 17:09:21 +03:00
Andrey
8296e9a32b add FreeRTOS support for PIThread PIMutex PIConditionVariable 2022-01-21 14:15:42 +03:00
Andrey
7403ee67be gitignore 2022-01-20 16:54:20 +03:00
Andrey
cde2341c1f fix freertos includes 2022-01-20 16:46:04 +03:00
Andrey
542f180d9d add Freertos dependency 2022-01-17 18:39:57 +03:00
86130d7105 compiled for esp32 2022-01-15 14:54:36 +03:00
Andrey
c9e329d27d rename PIInit BuildOption 2022-01-14 18:51:37 +03:00
Andrey
d4c6c410da some fixes 2022-01-14 18:25:41 +03:00
Andrey
a7df53fbfe platformio_pre.py 2022-01-14 18:15:56 +03:00
Andrey
0504fa187e define PIP_MICRO
detect AVR_GCC
add library.json
2022-01-14 14:37:51 +03:00
1d9a39f792 piCompare 2022-01-10 17:10:41 +03:00
cbdaabee4a some build fixes 2022-01-07 01:58:38 +03:00
3c8ccf357b PIFile::openTemporary on Windows
PIPair from std::tuple
2021-12-24 14:41:18 +03:00
Andrey
92b20f6f46 PIByteArray getRange 2021-11-16 15:22:03 +03:00
04d7ed77d9 Merge pull request 'condvar_use' (#82) from condvar_use into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/82
2021-11-16 14:49:52 +03:00
a2a205cfd2 version 2.33.0
piMinSleep() method
2021-11-16 14:43:57 +03:00
d3b6597042 PIMap range-for decomposition declaration support 2021-11-01 23:29:42 +03:00
Andrey
48c885e12a PIThreadNotifier, rewrite PIObject::deleteLater()
tests for PIThreadNotifier and PIObject::deleteLater()
2021-10-29 18:20:48 +03:00
Andrey
6e5a5a6ade remove msleep, clean PIConditionVariable, rewrite pipipelinethread, etc... 2021-10-29 16:52:03 +03:00
21e03fc8cb flags 2021-10-27 10:53:27 +03:00
b85de0d704 work with PIFile::openTemporary() on Windows 2021-10-26 13:50:27 +03:00
peri4
f781cc3846 binary log improvements 2021-10-21 18:48:01 +03:00
peri4
1cb3d4ffe9 PIBinaryLog fix 2021-10-14 12:45:01 +03:00
peri4
9293706634 PISerial 14400 baudrate only for Windows 2021-10-08 22:11:47 +03:00
peri4
fde6bdf17f PISerial 14400 baudrate 2021-10-08 22:02:51 +03:00
Andrey
a1c1fd8339 Merge branch 'master' of https://git.shs.tools/SHS/pip 2021-10-08 15:16:19 +03:00
Andrey
01b39dc75f pip_cmg fix macros name 2021-10-08 15:16:08 +03:00
07ec32c969 tests 2021-10-05 20:31:00 +03:00
042366e19e Merge branch 'PIMathMatrixTests1-10' 2021-10-04 22:14:38 +03:00
948a90fcd9 option revert 2021-10-04 22:14:15 +03:00
c404688bbd more safety for PIObject::Connection::disconnect() 2021-10-04 21:57:34 +03:00
aa76a15f40 version 2.32.0
PIObject::Connection struct
2021-10-04 21:50:49 +03:00
Andrey
ca20785b53 revert piDisconnectAll 2021-10-04 15:07:14 +03:00
Andrey
13d0b2f960 remove piDisconnectAll 2021-10-04 15:05:58 +03:00
Andrey
46571ac39f piDisconnectAll private 2021-10-04 14:18:23 +03:00
36d770ea2e Merge pull request 'piobject_tests' (#80) from piobject_tests into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/80
2021-10-04 12:11:51 +03:00
Andrey
bc7d129a9e piobject/connect.cpp tests 2021-10-04 12:07:01 +03:00
8accc28804 test fix 2021-09-30 19:28:30 +03:00
Andrey
62e130f91b disconnect test failed 2021-09-30 18:41:01 +03:00
a009221092 pidisconnect now work with lambdas 2021-09-30 16:21:28 +03:00
dedc35b466 new class PIThreadPoolLoop 2021-09-24 16:03:20 +03:00
5e33587703 PISerial::setBreak linux fix 2021-09-17 21:27:24 +03:00
950f6830da old gcc pithread fix 2021-09-17 21:20:21 +03:00
Andrey
19a8ca84e6 PIByteArray checksumPlain invert flag
fix PISerial setBreak
2021-09-16 16:18:20 +03:00
Andrey
ece3fb1536 PISerial setBreak 2021-09-16 12:18:17 +03:00
0d119502a8 PIDeque functions same as PIVector
code brush
fix indexOf and entries with start<0
2021-09-09 18:01:57 +03:00
cc5951cfc3 PIVector getRange removeWhere 2021-09-09 17:38:28 +03:00
61d42e0ac5 PIVector: map, reduce
rename arguments in uniform style
2021-09-07 18:29:09 +03:00
127935086c PIVector: any, every, indexWhere, lastIndexWhere
start arg in indexOf, entries, lastIndexOf
and some code brush
2021-09-07 17:29:24 +03:00
76ed60edf3 code brush 2021-09-07 15:39:44 +03:00
3b0a1c70fe documentation fix 2021-09-03 17:12:46 +03:00
186e07e45d PICodeInfo::EnumInfo toPIVariantEnum 2021-09-03 16:19:57 +03:00
047cff7d6e version 2021-09-03 12:42:29 +03:00
305275e3ac PICodeParser namespaces fix 2021-09-03 11:39:26 +03:00
efb0d5f4f9 PICodeParser predefined PIP macros 2021-09-03 11:20:38 +03:00
991a074538 version 2.30
PIStreamPacker remove progresses
picloud various fixes
2021-09-01 23:48:13 +03:00
f82b6c12ee cloud_dispatcher patch 2021-09-01 22:43:40 +03:00
00edfa4ef0 cloud data send optimize 2021-09-01 17:48:58 +03:00
35a3ce6402 picloudtcp.cpp revert some mutex 2021-09-01 10:56:11 +03:00
be3ce454a0 picloud multithread fix 2021-08-31 19:40:22 +03:00
4c85206cfa version 2021-08-23 14:07:45 +03:00
5ecdcbe46e Merge pull request 'cloud_debug' (#78) from cloud_debug into master
Reviewed-on: https://git.shs.tools/SHS/pip/pulls/78
2021-08-23 13:58:08 +03:00
c937d7251a it works 2021-08-23 13:56:21 +03:00
1cc46468c1 fail 2021-08-20 18:30:19 +03:00
5cc8ef1eb0 fail reconnect 2021-08-20 18:25:59 +03:00
99e135caa2 PICloudClient disconnect 2021-08-20 17:22:25 +03:00
9de7045d63 picloud revert to condvars and fix 2021-08-20 16:36:28 +03:00
0e65151e9f PIEthernet error 232
PICloud many fixes
PIBroadcast recursive fix
2021-08-20 10:55:47 +03:00
3c20728210 version 2021-08-19 18:29:05 +03:00
4c0530d89a picloud ping and fix big bugs 2021-08-19 18:13:05 +03:00
f5af8a1da9 disable autostart pibroadcast 2021-08-19 15:02:30 +03:00
44b9c37391 PICloudClient now soft stop thread when closed
last cmake changes
2021-08-16 22:30:56 +03:00
97b0b6fc0c picloud hash key 2021-08-12 22:05:02 +03:00
1a2e9afaef PIVector compare operators 2021-08-12 21:52:14 +03:00
39a3a23a24 PIByteArray compare operators 2021-08-12 21:41:22 +03:00
ee131921a0 add PIByteArray operator <, fix picloud 2021-08-12 20:22:43 +03:00
f8818c8537 picloud patch 2021-08-12 19:50:17 +03:00
b07242226e Tests1-10 2021-02-25 15:41:20 +03:00
387 changed files with 63262 additions and 36450 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

3
.gitignore vendored
View File

@@ -2,4 +2,5 @@
/.svn
/doc/rtf
_unsused
CMakeLists.txt.user*
CMakeLists.txt.user*
/include

View File

@@ -5,7 +5,7 @@
*/
#define lapi_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lcode_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lctype_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define ldebug_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define ldo_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define ldump_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lfunc_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lgc_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define llex_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lmem_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lobject_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lopcodes_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lparser_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lstate_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lstring_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define ltable_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define ltm_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lundump_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lvm_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -5,7 +5,7 @@
*/
#define lzio_c
#define LUA_CORE
#include "lprefix.h"

View File

@@ -1,22 +1,59 @@
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip)
set(pip_MAJOR 2)
set(pip_MINOR 28)
set(pip_REVISION 1)
set(pip_SUFFIX )
set(pip_COMPANY SHS)
set(pip_DOMAIN org.SHS)
project(PIP)
set(PIP_MAJOR 3)
set(PIP_MINOR 19)
set(PIP_REVISION 1)
set(PIP_SUFFIX )
set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS)
set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT)
set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cmake-download/CMakeLists.txt"
"# This file was generated by PIP CMake, don`t edit it!
cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE)
include(ExternalProject)
ExternalProject_Add(cmake
GIT_REPOSITORY https://git.shstk.ru/SHS/cmake.git
GIT_TAG \"origin/master\"
GIT_CONFIG \"advice.detachedHead=false\"
SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
BINARY_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\"
INSTALL_COMMAND \"\"
TEST_COMMAND \"\"
)
")
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
if(result)
message(FATAL_ERROR "CMake step for cmake failed: ${result}")
endif()
execute_process(COMMAND "${CMAKE_COMMAND}" --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
if(result)
message(FATAL_ERROR "Build step for cmake failed: ${result}")
endif()
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\" --target install)")
set(GIT_CMAKE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake-src")
endif()
if ("x${CMAKE_MODULE_PATH}" STREQUAL "x")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
endif()
if (NOT "x${GIT_CMAKE_DIR}" STREQUAL "x")
list(APPEND CMAKE_MODULE_PATH "${GIT_CMAKE_DIR}")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
include(CheckFunctionExists)
include(PIPMacros)
include(SHSTKMacros)
shstk_begin_project(pip PIP)
shstk_begin_project(PIP)
set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
@@ -24,14 +61,21 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_DEBUG ON)
else()
set(PIP_BUILD_DEBUG OFF)
endif()
# Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF)
option(INTROSPECTION "Build with introspection" OFF)
option(TESTS "Build tests and perform their before install step" OFF)
option(TESTS "Build tests and perform their before install step" ${PIP_BUILD_DEBUG})
option(COVERAGE "Build project with coverage info" OFF)
set(PIP_UTILS 1)
set(BUILDING_pip 1 PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11)
@@ -59,7 +103,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
set(CRES)
file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c")
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")
if (NOT "x${PHS}" STREQUAL "x")
list(REMOVE_ITEM HS ${PHS})
@@ -68,9 +112,14 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c")
list(APPEND CPPS ${ASRC})
endif()
#message("${NAME} HS = ${HS}")
list(APPEND HDRS ${HS})
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(_libs "${LIBS}")
if ("${NAME}" STREQUAL "main")
@@ -81,11 +130,11 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
string(TOUPPER "${_target}" DEF_NAME)
set(PIP_MSG_${NAME} "yes${MSG}")
import_version(${_target} pip)
set_deploy_property(${_target} ${pip_LIB_TYPE}
import_version(${_target} PIP)
set_deploy_property(${_target} ${PIP_LIB_TYPE}
LABEL "${LABEL}"
FULLNAME "${pip_DOMAIN}.${_target}"
COMPANY "${pip_COMPANY}"
FULLNAME "${PIP_DOMAIN}.${_target}"
COMPANY "${PIP_COMPANY}"
INFO "Platform-Independent Primitives")
make_rc(${_target} _RC)
@@ -102,7 +151,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
pip_resources(CRES "${RES}")
endif()
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})
if (NOT "x${RES}" STREQUAL "x")
add_dependencies(${_target} pip_rc)
@@ -211,12 +260,10 @@ CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2)
# Check if build debug version
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_TYPE "Debug")
if (PIP_BUILD_DEBUG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
add_definitions(-DPIP_DEBUG)
else()
set(PIP_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif()
@@ -284,7 +331,7 @@ endif()
if(APPLE)
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
endif()
if ((NOT DEFINED LIBPROJECT) AND (DEFINED ANDROID_PLATFORM))
if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
include_directories(${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include)
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include")
@@ -320,7 +367,7 @@ if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /Ob2 /Ot /W0")
endif()
else()
set(${CMAKE_CXX_FLAGS} "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
if(DEFINED ENV{QNX_HOST} OR PIP_FREERTOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32")
endif()
@@ -411,17 +458,16 @@ if (NOT CROSSTOOLS)
endif()
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
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}")
if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
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()
@@ -443,15 +489,19 @@ if (NOT CROSSTOOLS)
endif()
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr})
# Test program
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)
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_cloud pip_lua)
target_link_libraries(pip_test pip)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
endif()
endif()
else()
@@ -525,6 +575,7 @@ if(NOT PIP_FREERTOS)
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
add_subdirectory("utils/value_tree_translator")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
@@ -550,25 +601,38 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
include(PIPDocumentation)
find_package(Doxygen)
if(DOXYGEN_FOUND)
set(DOXY_PROJECT_NUMBER "${pip_VERSION}")
set(DOXY_QHP_CUST_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_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DEFINES "${PIP_EXPORTS}")
foreach (_m "console" "usb" "compress" "crypt" "cloud" "fftw" "opencl" "io_utils" "lua")
string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach()
set(DOXY_PROJECT_NUMBER "${PIP_VERSION}")
set(DOXY_QHP_CUST_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_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc")
if ("x${DOC_LANG}" STREQUAL "x")
set(DOXY_OUTPUT_LANGUAGE English)
set(DOXY_OUTPUT_DIR en)
else()
set(DOXY_OUTPUT_LANGUAGE ${DOC_LANG})
set(DOXY_OUTPUT_DIR ${DOC_DIR})
endif()
if(DOXYGEN_DOT_EXECUTABLE)
string(REPLACE "\\" "" _DOT_PATH "${DOXYGEN_DOT_PATH}")
string(REPLACE "\\" "/" _DOT_PATH "${DOXYGEN_DOT_PATH}")
set(DOXY_DOT_PATH "\"${_DOT_PATH}\"")
set(DOXY_MSCGEN_PATH "\"${_DOT_PATH}\"")
set(DOXY_DIA_PATH "\"${_DOT_PATH}\"")
endif()
set(DOXY_INPUT)
foreach(F ${PIP_MAIN_FOLDERS})
list(APPEND DOXY_INPUT "\"${F}\"")
endforeach(F)
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\"")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${DOXY_INPUT}")
string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS};DOXYGEN;PIOBJECT;PIOBJECT_SUBCLASS")
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\";\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pages\"")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${PIP_INCLUDES}")
string(REPLACE ";" " " DOXY_DEFINES "${DOXY_DEFINES}")
add_documentation(doc doc/Doxyfile.in)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL)
endif()
@@ -595,9 +659,9 @@ endmacro()
list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
message("----------PIP----------")
message(" Version: ${pip_VERSION} ")
message(" Linkage: ${pip_LIB_TYPE_MSG}")
message(" Type : ${pip_BUILD_TYPE}")
message(" Version: ${PIP_VERSION} ")
message(" Linkage: ${PIP_LIB_TYPE_MSG}")
message(" Type : ${CMAKE_BUILD_TYPE}")
if (NOT LOCAL)
message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else()

View File

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

View File

@@ -20,40 +20,35 @@ main library
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
include(SHSTKMacros)
shstk_set_find_dirs(pip)
if(PIP_DIR)
list(APPEND pip_LIBDIR "${PIP_DIR}/lib")
list(APPEND pip_INCDIR "${PIP_DIR}/include/pip")
list(APPEND pip_BINDIR "${PIP_DIR}/bin")
endif()
shstk_set_find_dirs(PIP)
set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
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(_bins "pip_cmg;pip_rc;deploy_tool")
#get_target_property(_path pip BINARY_DIR)
#get_target_property(_path pip LIBRARY_OUTPUT_NAME)
#message("${_path}")
#set(PIP_LIBRARY "$<TARGET_FILE_DIR:pip>/$<TARGET_FILE_NAME:pip>" CACHE STRING "")
set(PIP_LIBRARY pip CACHE STRING "")
#set(PIP_LIBRARY "$<TARGET_FILE_DIR:pip>/$<TARGET_FILE_NAME:pip>" CACHE STRING "")
set(PIP_LIBRARY pip CACHE STRING "")
set(PIP_FOUND ON CACHE BOOL "")
else()
find_library(PIP_LIBRARY pip HINTS ${pip_LIBDIR})
find_library(PIP_LIBRARY pip HINTS ${PIP_LIBDIR})
foreach (_l ${__libs})
find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${pip_LIBDIR})
find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${PIP_LIBDIR})
endforeach()
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_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "")
set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "")
else()
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_DEPLOY_TOOL deploy_tool${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_DEPLOY_TOOL deploy_tool${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
endif()
if (NOT PIP_LIBRARY)
if(PIP_FIND_REQUIRED)
@@ -63,7 +58,7 @@ if (NOT PIP_LIBRARY)
endif()
set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}")
set(_PIP_ADD_LIBS_ "")
if (NOT BUILDING_pip)
if (NOT BUILDING_PIP)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
find_library(DL_LIBRARY dl)
list(APPEND PIP_LIBRARY ${DL_LIBRARY})
@@ -71,14 +66,18 @@ if (NOT BUILDING_pip)
find_library(PTHREAD_LIBRARY pthread)
find_library(UTIL_LIBRARY util)
set(_PIP_ADD_LIBS_ ${PTHREAD_LIBRARY} ${UTIL_LIBRARY})
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT PIP_FREERTOS))
find_library(RT_LIBRARY rt)
list(APPEND _PIP_ADD_LIBS_ ${RT_LIBRARY})
endif()
list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_})
endif()
endif()
endif()
if (NOT BUILDING_pip)
shstk_find_header(pip PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}")
set(PIP_INCLUDES "${pip_INCLUDES}" CACHE STRING "")
if (NOT BUILDING_PIP)
shstk_find_header(PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}")
set(PIP_INCLUDES "${PIP_INCLUDES}" CACHE STRING "")
endif()
if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION)
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
@@ -104,10 +103,10 @@ set(__deps_io_utils "PIP::Crypt")
set(__deps_cloud "PIP::IOUtils")
if (BUILDING_pip)
if (BUILDING_PIP)
if (NOT SET_TARGETS_pip)
set(SET_TARGETS_pip ON CACHE BOOL "")
if (NOT SET_TARGETS_PIP)
set(SET_TARGETS_PIP ON CACHE BOOL "")
#message("create aliases")
if((NOT TARGET PIP) AND PIP_LIBRARY)
#message("alias PIP = pip")
@@ -129,7 +128,7 @@ else()
add_library(PIP UNKNOWN IMPORTED)
set_target_properties(PIP PROPERTIES
IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}"
INTERFACE_INCLUDE_DIRECTORIES "${pip_INCLUDES}"
INTERFACE_INCLUDE_DIRECTORIES "${PIP_INCLUDES}"
INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}")
#message("imported PIP = ${PIP_LIBRARY}")
endif()

View File

@@ -1,7 +1,7 @@
macro(ADD_DOCUMENTATION TARGET DOXYGEN_CONFIG_FILE)
if(DOXYGEN_FOUND)
configure_file("${PROJECT_SOURCE_DIR}/${DOXYGEN_CONFIG_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/doxyfile-${TARGET}")
add_custom_target("genereate.${TARGET}" COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile-${TARGET})
add_custom_target("genereate.${TARGET}" COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/doc/html" COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile-${TARGET})
add_custom_target("${TARGET}" COMMAND ${CMAKE_COMMAND} -D COMPONENT=doc -P cmake_install.cmake)
add_dependencies("${TARGET}" "genereate.${TARGET}")
else(DOXYGEN_FOUND)

View File

@@ -1,4 +1,4 @@
# Doxyfile 1.8.15
# Doxyfile 1.9.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "Platform-Independent Primitives"
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
PROJECT_LOGO =
PROJECT_LOGO = ${DOXY_LOGO_PATH}
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
@@ -91,7 +91,7 @@ ALLOW_UNICODE_NAMES = NO
# Ukrainian and Vietnamese.
# The default value is: English.
OUTPUT_LANGUAGE = English
OUTPUT_LANGUAGE = ${DOXY_OUTPUT_LANGUAGE}
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
@@ -158,7 +158,7 @@ INLINE_INHERITED_MEMB = NO
# shortest path that makes the file name unique will be used
# The default value is: YES.
FULL_PATH_NAMES = YES
FULL_PATH_NAMES = NO
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
@@ -197,10 +197,20 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
# /***************
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
# Javadoc-style will behave just like regular comments and it will not be
# interpreted by doxygen.
# The default value is: NO.
JAVADOC_BANNER = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
# requiring an explicit @brief command for a brief description.)
# requiring an explicit \brief command for a brief description.)
# The default value is: NO.
QT_AUTOBRIEF = NO
@@ -215,7 +225,15 @@ QT_AUTOBRIEF = NO
# not recognized any more.
# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
MULTILINE_CPP_IS_BRIEF = YES
# By default Python docstrings are displayed as preformatted text and doxygen's
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
# doxygen's special commands can be used and the contents of the docstring
# documentation blocks is shown as doxygen documentation.
# The default value is: YES.
PYTHON_DOCSTRING = YES
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
@@ -256,12 +274,6 @@ ALIASES = "handlers=\name Handlers" \
"events=\name Events" \
"ioparams=\name Configurable parameters"
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@@ -302,19 +314,22 @@ OPTIMIZE_OUTPUT_SLICE = NO
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is
# Fortran), use: inc=Fortran f=C.
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
# the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
EXTENSION_MAPPING =
@@ -332,7 +347,7 @@ MARKDOWN_SUPPORT = YES
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 0.
# Minimum value: 0, maximum value: 99, default value: 5.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0
@@ -353,7 +368,7 @@ AUTOLINK_SUPPORT = YES
# diagrams that involve STL classes more complete and accurate.
# The default value is: NO.
BUILTIN_STL_SUPPORT = NO
BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
@@ -448,6 +463,19 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1,
# which efficively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -468,6 +496,12 @@ EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
# The default value is: NO.
EXTRACT_PRIV_VIRTUAL = YES
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
@@ -505,6 +539,13 @@ EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = NO
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
RESOLVE_UNNAMED_PARAMS = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
@@ -522,8 +563,8 @@ HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# declarations. If set to NO, these declarations will be included in the
# documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = YES
@@ -542,11 +583,18 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# able to match the capabilities of the underlying filesystem. In case the
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
CASE_SENSE_NAMES = NO
@@ -569,14 +617,14 @@ HIDE_COMPOUND_REFERENCE= NO
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
SHOW_INCLUDE_FILES = NO
SHOW_INCLUDE_FILES = YES
# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
# grouped member an include statement to the documentation, telling the reader
# which file to include in order to use the member.
# The default value is: NO.
SHOW_GROUPED_MEMB_INC = NO
SHOW_GROUPED_MEMB_INC = YES
# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
# files with double quotes in the documentation rather than with sharp brackets.
@@ -785,7 +833,10 @@ WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
WARN_AS_ERROR = NO
@@ -821,8 +872,8 @@ INPUT = ${DOXY_INPUT}
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
@@ -835,46 +886,20 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
# *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
FILE_PATTERNS = *.c \
*.cpp \
*.c++ \
*.d \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.f90 \
*.f \
*.for \
*.vhd \
*.vhdl
*.md
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
@@ -1087,16 +1112,22 @@ USE_HTAGS = NO
VERBATIM_HEADERS = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
# YES then doxygen will add the directory of each input to the include path.
# The default value is: YES.
CLANG_ADD_INC_PATHS = YES
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
@@ -1106,10 +1137,13 @@ CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
# were built. This is equivalent to specifying the "-p" option to a clang tool,
# such as clang-check. These options will then be passed to the parser.
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the -p option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
@@ -1126,13 +1160,6 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
@@ -1156,7 +1183,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = html
HTML_OUTPUT = html/${DOXY_OUTPUT_DIR}
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
@@ -1239,7 +1266,7 @@ HTML_EXTRA_FILES =
# Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 246
HTML_COLORSTYLE_HUE = 221
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A
@@ -1247,7 +1274,7 @@ HTML_COLORSTYLE_HUE = 246
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 79
HTML_COLORSTYLE_SAT = 100
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100
@@ -1271,9 +1298,9 @@ HTML_TIMESTAMP = YES
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via Javascript. If disabled, the navigation index will
# are dynamically created via JavaScript. If disabled, the navigation index will
# consists of multiple levels of tabs that are statically embedded in every HTML
# page. Disable this option to support browsers that do not have Javascript,
# page. Disable this option to support browsers that do not have JavaScript,
# like the Qt help browser.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1299,14 +1326,15 @@ HTML_DYNAMIC_SECTIONS = NO
# Minimum value: 0, maximum value: 9999, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_INDEX_NUM_ENTRIES = 100
HTML_INDEX_NUM_ENTRIES = 1
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# environment (see:
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# create a documentation set, doxygen will generate a Makefile in the HTML
# output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
@@ -1329,7 +1357,7 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_BUNDLE_ID = ${DOXY_DOMAIN}
# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
@@ -1337,19 +1365,19 @@ DOCSET_BUNDLE_ID = org.doxygen.Project
# The default value is: org.doxygen.Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_ID = ${DOXY_DOMAIN}
# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
# The default value is: Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_NAME = Publisher
DOCSET_PUBLISHER_NAME = PIP
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
# (see:
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@@ -1379,7 +1407,7 @@ CHM_FILE =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# (YES) or that it should be included in the main .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1420,11 +1448,12 @@ GENERATE_QHP = YES
# the HTML output folder.
# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE = pip.qch
QCH_FILE = pip_${DOXY_OUTPUT_DIR}.qch
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1432,8 +1461,8 @@ QHP_NAMESPACE = PIP
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# Folders (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1441,30 +1470,30 @@ QHP_VIRTUAL_FOLDER = PIP
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME = PIP
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS = ${DOXY_QHP_CUST_FILTER_ATTRS}
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS = ${DOXY_QHP_SECT_FILTER_ATTRS}
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# The QHG_LOCATION tag can be used to specify the location (absolute path
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION = qhelpgenerator
@@ -1487,7 +1516,7 @@ GENERATE_ECLIPSEHELP = NO
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
ECLIPSE_DOC_ID = org.doxygen.Project
ECLIPSE_DOC_ID = PIP
# If you want full control over the layout of the generated HTML pages it might
# be necessary to disable the index and replace it with your own. The
@@ -1515,7 +1544,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = YES
GENERATE_TREEVIEW = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
@@ -1541,6 +1570,17 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
# the HTML output. These images will generally look nicer at scaled resolutions.
# Possible values are: png (the default) and svg (looks nicer but requires the
# pdf2svg or inkscape tool).
# The default value is: png.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FORMULA_FORMAT = png
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@@ -1561,8 +1601,14 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
FORMULA_MACROFILE =
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# https://www.mathjax.org) which uses client side Javascript for the rendering
# https://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@@ -1574,7 +1620,7 @@ USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
@@ -1590,7 +1636,7 @@ MATHJAX_FORMAT = HTML-CSS
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
@@ -1604,7 +1650,8 @@ MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
@@ -1629,10 +1676,10 @@ MATHJAX_CODEFILE =
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
SEARCHENGINE = NO
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@@ -1651,7 +1698,8 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/).
# Xapian (see:
# https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1664,8 +1712,9 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# Xapian (see:
# https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
@@ -1736,13 +1785,14 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX.
# generate index for LaTeX. In case there is no backslash (\) as first character
# it will be automatically added in the LaTeX code.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: \makeindex.
# The default value is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_MAKEINDEX_CMD = \makeindex
LATEX_MAKEINDEX_CMD = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
@@ -1828,9 +1878,11 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# files. Set this option to YES, to get a higher quality PDF documentation.
#
# See also section LATEX_CMD_NAME for selecting the engine.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -2164,7 +2216,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = ${DOXY_DEFINES}
PREDEFINED = DOXYGEN PIOBJECT PIOBJECT_SUBCLASS PIIODEVICE NO_COPY_CLASS ${DOXY_DEFINES}
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
@@ -2209,7 +2261,7 @@ TAGFILES =
# tag file that is based on the input files it reads. See section "Linking to
# external documentation" for more information about the usage of tag files.
GENERATE_TAGFILE = doc/pip.cfg
GENERATE_TAGFILE = doc/html/${DOXY_OUTPUT_DIR}/pip.cfg
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
@@ -2230,13 +2282,7 @@ EXTERNAL_GROUPS = YES
# be listed.
# The default value is: YES.
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of 'which perl').
# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
EXTERNAL_PAGES = NO
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
@@ -2251,15 +2297,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see:
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH = ${DOXY_MSCGEN_PATH}
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2357,10 +2394,32 @@ UML_LOOK = NO
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 12
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_WRAP_THRESHOLD = 17
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
@@ -2550,9 +2609,11 @@ DOT_MULTI_TARGETS = YES
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc and
# plantuml temporary files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES

View File

@@ -9,8 +9,14 @@ struct S {
};
// Operators
PIByteArray & operator <<(PIByteArray & b, const S & s) {b << s.i << s.f << s.s; return b;}
PIByteArray & operator >>(PIByteArray & b, S & s) {b >> s.i >> s.f >> s.s; return b;}
PIByteArray & operator<<(PIByteArray & b, const S & s) {
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]
//! [write]
// Write chunk stream
@@ -22,10 +28,7 @@ PIVector<float> f;
f << -1. << 2.5 << 11.;
// write some data to empty stream
PIChunkStream cs;
cs << cs.chunk(1, int(10))
<< cs.chunk(2, PIString("text"))
<< cs.chunk(4, f)
<< cs.chunk(3, s);
cs << cs.chunk(1, int(10)) << 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 ...
//! [write]
//! [read]
@@ -42,14 +45,14 @@ while (!cs2.atEnd()) {
case 1: i = cs2.getData<int>(); break;
case 2: str = cs2.getData<PIString>(); break;
case 3: s = cs2.getData<S>(); break;
case 4: f = cs2.getData<PIVector<float> >(); break;
case 4: f = cs2.getData<PIVector<float>>(); break;
}
}
piCout << i << str << f << s.i << s.f << s.s;
//! [read]
//! [write_new]
PIByteArray & operator <<(PIByteArray & s, const S & value) {
PIByteArray & operator<<(PIByteArray & s, const S & value) {
PIChunkStream cs;
cs.add(1, value.i).add(2, value.f).add(3, value.s);
s << cs.data();
@@ -57,11 +60,11 @@ PIByteArray & operator <<(PIByteArray & s, const S & value) {
}
//! [write_new]
//! [read_new]
PIByteArray & operator >>(PIByteArray & s, S & value) {
PIByteArray & operator>>(PIByteArray & s, S & value) {
PIChunkStream cs;
if (!cs.extract(s)) return s;
cs.readAll();
cs.get(1, value.i).get(2, value.f).get(3, value.s);
return b;
return s;
}
//! [read_new]

View File

@@ -1,25 +1,6 @@
#include "pip.h"
//! [main]
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
//! [main]
void _() {

View File

@@ -4,14 +4,17 @@ void _() {
//! [foreach]
PIVector<int> vec;
vec << 1 << 2 << 3;
piForeach (int & i, vec)
cout << i << ", ";
// 1, 2, 3,
piForeach (int & i, vec)
i++;
piForeach (int & i, vec)
cout << i << ", ";
// 2, 3, 4,
piForeach (int & i, vec) piCout << i;
// 1
// 2
// 3
piForeach (int & i, vec) i++;
piForeach (int & i, vec) piCout << i;
// 2
// 3
// 4
//! [foreach]
//! [foreachC]
PIVector<int> vec;

View File

@@ -4,7 +4,7 @@
inline PICout operator <<(PICout s, const PIByteArray & ba) {
s.space(); // insert space after previous output
s.quote(); // ONLY if you want to quoted your type
s.setControl(0, true); // clear all features and
s.saveAndSetControls(0); // clear all features and
// save them to stack,
// now it`s behavior similar to std::cout
@@ -12,7 +12,7 @@ inline PICout operator <<(PICout s, const PIByteArray & ba) {
for (uint i = 0; i < ba.size(); ++i)
s << ba[i];
s.restoreControl(); // restore features from stack
s.restoreControls(); // restore features from stack
s.quote(); // ONLY if you want to quoted your type
return s;
}

View File

@@ -3,25 +3,24 @@ void _() {
//! [0]
class SomeIO: public PIIODevice {
PIIODEVICE(SomeIO)
PIIODEVICE(SomeIO, "myio")
public:
SomeIO(): PIIODevice() {}
protected:
bool openDevice() {
bool openDevice() override {
// open your device here
return if_success;
}
int read(void * read_to, int max_size) {
ssize_t readDevice(void * read_to, ssize_t max_size) override {
// read from your device here
return readed_bytes;
}
int write(const void * data, int max_size) {
ssize_t writeDevice(const void * data, ssize_t max_size) override {
// write to your device here
return written_bytes;
}
PIString fullPathPrefix() const {return "myio";}
void configureFromFullPath(const PIString & full_path) {
// parse full_path and configure device there
void configureFromFullPathDevice(const PIString & full_path) override {
// parse full_path and configure device here
}
};
REGISTER_DEVICE(SomeIO)
@@ -39,7 +38,7 @@ ser.configure("example.conf", "dev");
//! [configureDevice]
class SomeIO: public PIIODevice {
...
bool configureDevice(const void * e_main, const void * e_parent) {
bool configureDevice(const void * e_main, const void * e_parent) override {
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep));

View File

@@ -2,8 +2,5 @@
void _() {
//! [main]
mutex.lock();
// ... your code here
mutex.unlock();
//! [main]
}

View File

@@ -5,8 +5,8 @@ class ObjectA: public PIObject {
PIOBJECT(ObjectA)
public:
EVENT_HANDLER1(void, handlerA, const PIString & , str) {piCoutObj << "handler A:" << str;}
EVENT2(eventA2, int, i, float, f);
EVENT1(eventA1, const PIString & , str);
EVENT2(eventA2, int, i, float, f);
};
class ObjectB: public PIObject {
@@ -26,7 +26,11 @@ int main(int argc, char * argv[]) {
CONNECT1(void, PIString, &obj_b, eventB, &obj_a, handlerA);
obj_b.eventB("event to handler");
CONNECT1(void, PIString, &obj_a, eventA1, &obj_b, eventB);
CONNECTU(&obj_a, eventA1, &obj_b, eventB);
obj_a.eventA1("event to event");
obj_a.piDisconnect("eventA1");
CONNECTL(&obj_a, eventA1, ([](const PIString & str){piCout << str;}));
obj_a.eventA1("event to lambda");
};
//! [main]

View File

@@ -1,348 +0,0 @@
#include "pip.h"
void _() {
//! [PIString(char * )]
PIString s("string");
//! [PIString(char * )]
//! [PIString(wchar_t * )]
PIString s(L"string");
//! [PIString(wchar_t * )]
//! [PIString(char * , int)]
PIString s("string", 3); // s = "str"
//! [PIString(char * , int)]
//! [PIString(int, char)]
PIString s(5, 'p'); // s = "ppppp"
//! [PIString(int, char)]
//! [PIString(int, PIChar)]
PIString s(5, ""); // s = "№№№№№"
//! [PIString(int, PIChar)]
//! [PIString::char*]
PIString s("pip");
cout << (char*)s << endl; // pip
//! [PIString::char*]
//! [PIString::<<(PIString)]
PIString s("this"), s1(" is"), s2(" string");
s << s1 << s2; // s = "this is string"
//! [PIString::<<(PIString)]
//! [PIString::<<(PIChar)]
PIString s("stri");
s << PIChar('n') << PIChar('g'); // s = "string"
//! [PIString::<<(PIChar)]
//! [PIString::<<(char * )]
PIString s("this");
s << " is" << " string"; // s = "this is string"
//! [PIString::<<(char * )]
//! [PIString::<<(wchar_t * )]
PIString s;
s << L"№ -" << " number"; // s = "№ - number"
//! [PIString::<<(wchar_t * )]
//! [PIString::<<(int)]
PIString s("ten - ");
s << 10; // s = "ten - 10"
//! [PIString::<<(int)]
//! [PIString::mid]
PIString s("0123456789");
piCout << s.mid(-2, -1); // s = "0123456789"
piCout << s.mid(-2, 4); // s = "01"
piCout << s.mid(3, -1); // s = "3456789"
piCout << s.mid(3, 4); // s = "3456"
//! [PIString::mid]
//! [PIString::left]
PIString s("0123456789");
piCout << s.left(-1); // s = ""
piCout << s.left(1); // s = "0"
piCout << s.left(5); // s = "01234"
piCout << s.left(15); // s = "0123456789"
//! [PIString::left]
//! [PIString::right]
PIString s("0123456789");
piCout << s.right(-1); // s = ""
piCout << s.right(1); // s = "9"
piCout << s.right(5); // s = "56789"
piCout << s.right(15); // s = "0123456789"
//! [PIString::right]
//! [PIString::cutMid]
PIString s("0123456789");
s.cutMid(1, 3);
piCout << s; // s = "0456789"
s.cutMid(-1, 3);
piCout << s; // s = "56789"
s.cutMid(3, -1);
piCout << s; // s = "567"
//! [PIString::cutMid]
//! [PIString::cutLeft]
PIString s("0123456789");
s.cutLeft(1);
piCout << s; // s = "123456789"
s.cutLeft(3);
piCout << s; // s = "456789"
s.cutLeft(30);
piCout << s; // s = ""
//! [PIString::cutLeft]
//! [PIString::cutRight]
PIString s("0123456789");
s.cutRight(1);
piCout << s; // s = "012345678"
s.cutRight(3);
piCout << s; // s = "012345"
s.cutRight(30);
piCout << s; // s = ""
//! [PIString::cutRight]
//! [PIString::trim]
PIString s(" string ");
s.trim();
piCout << s; // s = "string"
//! [PIString::trim]
//! [PIString::trimmed]
PIString s(" string ");
piCout << s.trimmed(); // s = "string"
piCout << s; // s = " string "
//! [PIString::trimmed]
//! [PIString::replace_0]
PIString s("0123456789");
s.replace(2, 3, "_cut_");
piCout << s; // s = "01_cut_56789"
s.replace(0, 1, "one_");
piCout << s; // s = "one_1_cut_56789"
//! [PIString::replace_0]
//! [PIString::replaced_0]
PIString s("0123456789");
piCout << s.replaced(2, 3, "_cut_"); // s = "01_cut_56789"
piCout << s.replaced(0, 1, "one_"); // s = "one_123456789"
//! [PIString::replaced_0]
//! [PIString::replace_1]
PIString s("pip string");
bool ok;
s.replace("string", "conf", &ok);
piCout << s << ok; // s = "pip conf", true
s.replace("PIP", "PlInPr", &ok);
piCout << s << ok; // s = "pip conf", false
//! [PIString::replace_1]
//! [PIString::replaced_1]
PIString s("pip string");
bool ok;
piCout << s.replace("string", "conf", &ok); // s = "pip conf", true
piCout << s.replace("PIP", "PlInPr", &ok); // s = "pip string", false
//! [PIString::replaced_1]
//! [PIString::replaceAll]
PIString s("substrings");
s.replaceAll("s", "_");
piCout << s; // s = "_ub_tring_"
//! [PIString::replaceAll]
//! [PIString::repeat]
PIString s(" :-) ");
s.repeat(3);
piCout << s; // :-) :-) :-)
//! [PIString::repeat]
//! [PIString::repeated]
PIString s(" :-) ");
piCout << s.repeated(3); // :-) :-) :-)
piCout << s; // :-)
//! [PIString::repeated]
//! [PIString::insert_0]
PIString s("pp");
s.insert(1, "i");
piCout << s; // s = "pip"
//! [PIString::insert_0]
//! [PIString::insert_1]
PIString s("pp");
s.insert(1, 'i');
piCout << s; // s = "pip"
//! [PIString::insert_1]
//! [PIString::insert_2]
PIString s("stg");
s.insert(2, "rin");
piCout << s; // s = "string"
//! [PIString::insert_2]
//! [PIString::expandRightTo]
PIString s("str");
s.expandRightTo(2, "_");
piCout << s; // s = "str"
s.expandRightTo(6, "_");
piCout << s; // s = "str___"
//! [PIString::expandRightTo]
//! [PIString::expandLeftTo]
PIString s("str");
s.expandLeftTo(2, "_");
piCout << s; // s = "str"
s.expandLeftTo(6, "_");
piCout << s; // s = "___str"
//! [PIString::expandLeftTo]
//! [PIString::reverse]
PIString s("0123456789");
s.reverse();
piCout << s; // s = "9876543210"
//! [PIString::reverse]
//! [PIString::reversed]
PIString s("0123456789");
piCout << s.reversed(); // s = "9876543210"
piCout << s; // s = "0123456789"
//! [PIString::reversed]
//! [PIString::elided]
piCout << PIString("123456789ABCDEF").elided(8, PIString::ElideLeft); // ..ABCDEF
piCout << PIString("123456789ABCDEF").elided(8, PIString::ElideCenter); // 123..DEF
piCout << PIString("123456789ABCDEF").elided(8, PIString::ElideRight); // 123456..
piCout << PIString("123456789ABCDEF").elided(8, 0.25); // 12..CDEF
//! [PIString::elided]
//! [PIString::lengthAscii]
piCout << PIString("0123456789").lengthAscii(); // 10
piCout << PIString("№1").lengthAscii(); // 3
//! [PIString::lengthAscii]
//! [PIString::data]
piCout << PIString("0123456789").data(); // 0123456789
piCout << PIString("№1").data(); // №1
//! [PIString::data]
//! [PIString::split]
PIString s("1 2 3");
piCout << s.split(" "); // {"1", "2", "3"}
//! [PIString::split]
//! [PIString::find]
PIString s("012345012345");
piCout << s.find("-"); // -1
piCout << s.find("3"); // 3
piCout << s.find("3", 4); // 9
piCout << s.find("3", 10); // -1
//! [PIString::find]
//! [PIString::findLast]
PIString s("012345012345");
piCout << s.find("-"); // -1
piCout << s.find("3"); // 9
piCout << s.find("3", 4); // 9
piCout << s.find("3", 10); // -1
//! [PIString::findLast]
//! [PIString::findAny]
piCout << PIString("1.str").findAny(".,:"); // 1
piCout << PIString("1,str").findAny(".,:"); // 1
piCout << PIString("1:str").findAny(".,:"); // 1
//! [PIString::findAny]
//! [PIString::findAnyLast]
piCout << PIString("str.0").findAny(".,:"); // 3
piCout << PIString("str,0").findAny(".,:"); // 3
piCout << PIString("str:0").findAny(".,:"); // 3
//! [PIString::findAnyLast]
//! [PIString::findWord]
PIString s("this is <PIP>");
piCout << s.find("this"); // 0
piCout << s.find("is"); // 5
piCout << s.find("PIP", 4); // -1
piCout << s.find("<PIP>", 10); // 8
//! [PIString::findWord]
//! [PIString::findCWord]
PIString s("this::is <PIP>");
piCout << s.find("this"); // 0
piCout << s.find("is"); // 6
piCout << s.find("PIP", 4); // 10
piCout << s.find("<PIP>", 10); // 9
//! [PIString::findCWord]
//! [PIString::toNumber]
piCout << PIString("123").toInt(); // 123
piCout << PIString("123").toInt(16); // 291
piCout << PIString("0x123").toInt(); // 291
piCout << PIString("1001").toInt(2); // 9
//! [PIString::toNumber]
//! [PIString::toFloat]
piCout << PIString("123").toFloat(); // 123
piCout << PIString("1.2E+2").toFloat(); // 120
piCout << PIString("0.01").toFloat(); // 0.01
//! [PIString::toFloat]
//! [PIString::setNumber]
PIString s;
s.setNumber(123);
piCout << s; // 123
s.setNumber(123, 16);
piCout << s; // 7B
//! [PIString::setNumber]
//! [PIString::setFloat]
PIString s;
s.setNumber(12.3);
piCout << s; // 12.3
//! [PIString::setFloat]
//! [PIString::setReadableSize]
PIString s;
s.setReadableSize(512);
piCout << s; // 512 B
s.setReadableSize(5120);
piCout << s; // 5.0 kB
s.setReadableSize(512000);
piCout << s; // 500.0 kB
s.setReadableSize(5120000);
piCout << s; // 4.8 MB
s.setReadableSize(512000000);
piCout << s; // 488.2 MB
s.setReadableSize(51200000000);
piCout << s; // 47.6 GB
//! [PIString::setReadableSize]
//! [PIString::fromNumber]
piCout << PIString::fromNumber(123); // 123
piCout << PIString::fromNumber(123, 16); // 7B
//! [PIString::fromNumber]
//! [PIString::fromFloat]
piCout << PIString::fromNumber(12.3); // 12.3
//! [PIString::fromFloat]
//! [PIString::readableSize]
piCout << PIString::readableSize(512); // 512 B
piCout << PIString::readableSize(5120); // 5.0 kB
piCout << PIString::readableSize(512000); // 500.0 kB
piCout << PIString::readableSize(5120000); // 4.8 MB
piCout << PIString::readableSize(512000000); // 488.2 MB
piCout << PIString::readableSize(51200000000); // 47.6 GB
//! [PIString::readableSize]
//! [PIString::takeSymbol]
PIString s("\t ! word");
piCout << s.takeSymbol(); // "!"
piCout << s.takeSymbol(); // "w"
piCout << s.takeSymbol(); // "o"
piCout << s; // "rd"
//! [PIString::takeSymbol]
//! [PIString::takeWord]
PIString s("some words\nnew line ");
piCout << s.takeWord(); // "some"
piCout << s.takeWord(); // "words"
piCout << s.takeWord(); // "new"
piCout << s; // " line "
//! [PIString::takeWord]
//! [PIString::takeLine]
PIString s("some words\nnew line \n\nend");
piCout << s.takeLine(); // "some words"
piCout << s.takeLine(); // "new line "
piCout << s.takeLine(); // ""
piCout << s; // "end"
//! [PIString::takeLine]
//! [PIString::takeNumber]
PIString s(" 0xFF -99 1.2E+5f 1000L");
piCout << s.takeNumber(); // "0xFF"
piCout << s.takeNumber(); // "-99"
piCout << s.takeNumber(); // "1.2E+5f"
piCout << s.takeNumber(); // "1000L"
piCout << s; // ""
//! [PIString::takeNumber]
//! [PIString::takeRange]
PIString s(" {figures{inside}}");
piCout << s.takeRange('{', '}'); // "figures{inside}"
piCout << s; // ""
s = "\"text\\\"shielded\" next";
piCout << s.takeRange('"', '"'); // "text\"shielded"
piCout << s; // " next"
//! [PIString::takeRange]
//! [PIStringList::join]
PIStringList sl("1", "2");
sl << "3";
piCout << sl.join(" < "); // 1 < 2 < 3
//! [PIStringList::join]
//! [PIStringList::removeStrings]
PIStringList sl("1", "2");
sl << "1" << "2" << "3";
piCout << sl; // {"1", "2", "1", "2", "3"}
piCout << sl.removeStrings("1"); // {"2", "2", "3"}
//! [PIStringList::removeStrings]
//! [PIStringList::removeDuplicates]
PIStringList sl("1", "2");
sl << "1" << "2" << "3";
piCout << sl; // {"1", "2", "1", "2", "3"}
piCout << sl.removeDuplicates(); // {"1", "2", "3"}
//! [PIStringList::removeDuplicates]
};

BIN
doc/images/pirect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

297
doc/pages/code_model.md Normal file
View File

@@ -0,0 +1,297 @@
\~english \page code_model Code generation
\~russian \page code_model Генерация кода
\~english
\~russian
# Введение
Кодогенерация помогает в случаях, когда нужен доступ к строковому представлению
сущностей (классов, перечислений, ...), либо автоматизированная де/сериализация
структур и классов.
Например, необходимо для создания интерфейса получить в готовом виде список
пар "имя" = "значение" от какого-либо перечисления, либо обойти список
вложенных в класс структур с дополнительными метками. Или просто описать
структуру любой сложности, пометить поля номерами и получить готовые операторы
де/сериализации для PIBinaryStream с возможностью будущих изменений и сохранением
обратной совместимости.
# pip_cmg
PIP предоставляет утилиту, которая берет на вход файлы исходного кода, пути
включения, параметры и макросы, и на выходе создает h/cpp пару файлов с
необходимым функционалом. В зависимости от параметров, в этих файлах будут
присутствовать секции:
* метаинформации о сущностях;
* операторы де/сериализации;
* возможность получить PIVariant любого члена структуры по имени.
Параметры обработки:
* -s - не следовать "#include" внутри файлов;
* -I<include_dir> - добавить папку включения (например, -I.. -I../some_dir -I/usr/include);
* -D<define> - добавить макрос, PICODE всегда объявлен (например, -DMY_DEFINE добавит макрос MY_DEFINE).
Параметры создания:
* -A - создать всё;
* -M - создать метаинформацию (имена и типы всех членов, иерархия включения);
* -E - создать перечисления (списки перечислений);
* -S - создать операторы де/сериализации;
* -G - создать методы получения значений переменных по именам;
* -o <output_file> - имя файлов модели без расширения (например, "ccm" - создадутся файлы "ccm.h" и "ccm.cpp")
# CMake
Для автоматизации кодогенерации существует CMake макрос pip_code_model, который сам вызывает pip_cmg и
следит за актуальностью модели.
Формат вызова макроса:
\code{.cmake}
pip_code_model(<out_var> file0 [file1 ...] [OPTIONS opt0 [opt1 ...] ] [NAME name])
\endcode
Параметры:
* out_var - имя переменной, куда будут записаны абсолютные пути сгенерённых файлов;
* file... - файлы для генерации, допускаются относительные или абсолютные пути;
* OPTIONS - передаваемые в pip_cmg параметры, например, "-Es";
* NAME - базовое имя файлов модели, если не указано, то используется "ccm_${PROJECT_NAME}".
Этот макрос сам включает все пути для PIP.
Для получения актуальных параметров pip_cmg можно вызывать "pip_cmg -v".
# Подробности
## Метаинформация
Метаинформация - это текстовое представление всех членов и методов структуры или класса C++.
Для доступа к ним используется PICODEINFO::classes().value("name"), который возвращает
указатель на структуру PICodeInfo::ClassInfo, содержащую всю информацию о сущности.
В любой структуре PICodeInfo есть поле "MetaMap meta", содержащее произвольные
данные, видимые для кодогенератора, но невидимые для компилятора.
Для этого используется макрос PIMETA(), который необходимо вписать после объявления
переменной, метода либо сущности, например:
\code{.cpp}
struct MyStruct: Header PIMETA(type=in,port=5005) {
ushort calcChecksum() const PIMETA(show=true);
bool checkChecksum() const;
void setChecksum();
uchar block_id PIMETA(type=int) = 0;
};
enum FOV { // Поле зрения
fovWide PIMETA(label="Широкое",angle=90),
fovNormal PIMETA(label="Нормальное",angle=60),
fovNarrow PIMETA(label="Узкое",angle=30)
};
\endcode
В этом примере в каждом месте, где указана PIMETA, её можно будет получить через "MetaMap meta".
## Перечисления
Перечисления записываются отдельно, для доступа к ним используется PICODEINFO::enums().value("name"),
который возвращает указатель на структуру PICodeInfo::EnumInfo, содержащую всю информацию о перечеслении.
## Операторы де/сериализации
Эти операторы создаются в h файле для всех сутрктур и классов, в которых есть хотя бы один член,
доступный для работы. Операторы работают с PIBinaryStream в двух вариантах - простом или через PIChunkStream.
Для каждой структуры можно указать режим де/сериализации с помощью фиксированного поля в PIMETA:
* нет указаний - работа через PIChunkStream;
* simple-stream - работа просто через PIBinaryStream;
* no-stream - не создавать операторы.
Например, для структуры
\code{.cpp}
struct DateTime {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
создадутся операторы
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(1, v.seconds);
cs << cs.chunk(2, v.minutes);
cs << cs.chunk(3, v.hours);
cs << cs.chunk(4, v.days);
cs << cs.chunk(5, v.months);
cs << cs.chunk(6, v.years);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 1: cs.get(v.seconds); break;
case 2: cs.get(v.minutes); break;
case 3: cs.get(v.hours); break;
case 4: cs.get(v.days); break;
case 5: cs.get(v.months); break;
case 6: cs.get(v.years); break;
}
}
return s;
}
\endcode
, где порядок id последовательнен.
Для структуры
\code{.cpp}
struct DateTime PIMETA(simple-stream) {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
создадутся операторы
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
s << v.seconds;
s << v.minutes;
s << v.hours;
s << v.days;
s << v.months;
s << v.years;
return s;
}
BINARY_STREAM_READ (DateTime) {
s >> v.seconds;
s >> v.minutes;
s >> v.hours;
s >> v.days;
s >> v.months;
s >> v.years;
return s;
}
\endcode
Для структуры
\code{.cpp}
struct DateTime PIMETA(no-stream) {
uchar seconds;
uchar minutes;
uchar hours;
uchar days;
uchar months;
uchar years;
};
\endcode
не создадутся операторы
В режиме работы через PIChunkStream также можно указать индивидуальные id,
что очень полезно для сохранения обратной совместимости структур разных версий:
Для структуры
\code{.cpp}
struct DateTime {
PIMETA(id=10) uchar seconds;
PIMETA(id=11) uchar minutes;
PIMETA(id=12) uchar hours;
PIMETA(id=20) uchar days;
PIMETA(id=21) uchar months;
PIMETA(id=22) uchar years;
};
\endcode
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(10, v.seconds);
cs << cs.chunk(11, v.minutes);
cs << cs.chunk(12, v.hours);
cs << cs.chunk(20, v.days);
cs << cs.chunk(21, v.months);
cs << cs.chunk(22, v.years);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 10: cs.get(v.seconds); break;
case 11: cs.get(v.minutes); break;
case 12: cs.get(v.hours); break;
case 20: cs.get(v.days); break;
case 21: cs.get(v.months); break;
case 22: cs.get(v.years); break;
}
}
return s;
}
\endcode
Если в этом режиме какую-либо переменную надо проигнорировать, то вместо
числа id можно указать "-":
\code{.cpp}
struct DateTime {
PIMETA(id=10) uchar seconds;
PIMETA(id=11) uchar minutes;
PIMETA(id=-) uchar hours;
PIMETA(id=20) uchar days;
PIMETA(id=21) uchar months;
PIMETA(id=-) uchar years;
};
\endcode
\code{.cpp}
BINARY_STREAM_WRITE(DateTime) {
PIChunkStream cs;
cs << cs.chunk(10, v.seconds);
cs << cs.chunk(11, v.minutes);
cs << cs.chunk(20, v.days);
cs << cs.chunk(21, v.months);
s << cs.data();
return s;
}
BINARY_STREAM_READ (DateTime) {
PIByteArray csba; s >> csba;
PIChunkStream cs(csba);
while (!cs.atEnd()) {
switch (cs.read()) {
case 10: cs.get(v.seconds); break;
case 11: cs.get(v.minutes); break;
case 20: cs.get(v.days); break;
case 21: cs.get(v.months); break;
}
}
return s;
}
\endcode
# Интеграция в проект
При использовании CMake достаточно включить содержимое переменной out_var в приложение
или библиотеку, и включить через "#include" сгенерированный заголовочный файл в нужном месте.
После этого перечисления и метаинформация будут загружены в момент запуска, до int main(),
а операторы станут доступны через заголовочный файл.
CMakeLists.txt:
\code{.cmake}
project(myapp)
pip_code_model(CCM "structures.h" OPTIONS "-EMs")
add_executable(${PROJECT_NAME} ${CPPS} ${CCM})
\endcode
C++:
\code{.cpp}
#include "ccm_myapp.h"
...
PICodeInfo::EnumInfo * ei = PICODEINFO::enums().value("MyEnum", 0);
if (ei) {
ei->members.forEach([](const PICodeInfo::EnumeratorInfo & e){piCout << e.name << "=" << e.value;});
}
\endcode

125
doc/pages/iostream.md Normal file
View File

@@ -0,0 +1,125 @@
\~english \page iostream Input/Output stream
\~russian \page iostream Поток ввода/вывода
\~english
\~russian
%PIBinaryStream представляет собой интерфейс бинарной сериализации.
Не может быть использован в чистом виде, только в виде миксина или
готовых классов: PIByteArray и PIIOBinaryStream.
Используется для сохранения или чтения любых данных. Простые типы читаются/пишутся
как блоки памяти, если не созданы конкретные операторы. Сложные типы
([нетривиальные](https://ru.cppreference.com/w/cpp/types/is_trivially_copyable))
обязаны иметь операторы ввода/вывода, иначе возникнет ошибка компиляции.
Также поддерживаются контейнеры с типами по таким же правилам.
Перечисления интерпретируются как int, логические типы как один байт.
Операторы сохранения добавляют данные в конец потока, а операторы извлечения
берут данные из его начала.
Для облегчения написания операторов есть макросы:
* BINARY_STREAM_FRIEND(T) - объявить операторы с доступом к приватному
содержимому типа T, необязателен;
* BINARY_STREAM_WRITE(T) - запись в поток, "s" - объект потока, "v" - объект типа T;
* BINARY_STREAM_READ(T) - чтение из потока, "s" - объект потока, "v" - объект типа T.
Пример:
\~\code{.cpp}
#include <pibytearray.h>
class MyType {
BINARY_STREAM_FRIEND(MyType);
public:
void setInt(int v) {m_i = v;}
int getInt() const {return m_i;}
void setString(PIString v) {m_s = v;}
PIString getString() const {return m_s;}
private:
int m_i = 0;
PIString m_s;
};
BINARY_STREAM_WRITE(MyType) {s << v.m_i << v.m_s; return s;}
BINARY_STREAM_READ (MyType) {s >> v.m_i >> v.m_s; return s;}
int main(int argc, char * argv[]) {
MyType t_read, t_write;
t_write.setInt(10);
t_write.setString("text");
PIByteArray data;
data << t_write;
piCout << data.toHex();
data >> t_read;
piCout << t_read.getInt() << t_read.getString();
piCout << data.toHex();
}
\endcode
\~english Result:
\~russian Результат:
\~\code{.cpp}
0a000000040000007400650078007400
10 text
\endcode
\~english
For store/restore custom data blocks this is PIMemoryBlock class. Stream
operators of this class simply store/restore data block to/from stream:
\~russian
Для сохранения/извлечения блоков произвольных данных используется класс PIMemoryBlock.
Потоковые операторы для него просто сохраняют/извлекают блоки байтов в/из потока:
\~\code{.cpp}
float a_read[10], a_write[10];
for (int i = 0; i < 10; ++i) {
a_read [i] = 0.f;
a_write[i] = i / 10.f;
}
PIByteArray data;
data << PIMemoryBlock(a_write, 10 * sizeof(float));
piCout << data.toHex();
data >> PIMemoryBlock(a_read, 10 * sizeof(float));
for (int i = 0; i < 10; ++i)
piCout << a_read[i];
\endcode
\~english Result:
\~russian Результат:
\~\code{.cpp}
00000000cdcccc3dcdcc4c3e9a99993ecdcccc3e0000003f9a99193f3333333fcdcc4c3f6666663f
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
\endcode
\~english
\~russian
Если при чтении из потока не хватило данных (например, закончился массив или файл), то проверка
объекта потока на wasReadError() вернёт true. Рекомендуется делать эту проверку после чтения
данных для корректной обработки ошибки.

44
doc/pages/main.md Normal file
View File

@@ -0,0 +1,44 @@
\~english \mainpage What is PIP
\~russian \mainpage Что такое PIP
\~english
PIP - Platform-Independent Primitives - is crossplatform library for C++ developers.
This library can help developers write non-GUI projects much more quickly, efficiently
and customizable than on pure C++.
Application written on PIP works the same on any system. One can read and write
any data types, serialize any types to device channels between any systems.
Many common data types, system primitives and devices implemented in this library.
PIP also tightly integrates with [CMake](https://cmake.org/) build system, providing handly search
main library, additional modules of PIP and several utilites. With
CMake with PIP one can easily generate and use code metainformation or
serialize custom types with it versions back-compatability.
Summary one can find at \ref summary page.
Basic using of PIP described at \ref using_basic page.
\~russian
PIP - Platform-Independent Primitives - кроссплатформенная библиотека для разработчиков на C++.
Эта библиотека поможет разработчику написать неграфическое приложение быстрее, эффективнее
и более гибко, чем на чистом C++.
Приложения, написанные на PIP, работают одинаково на многих системах. Можно читать и писать
любые типы данных, сериализовать любые типы в каналы устройств между любыми системами.
Многие типы данных, системные сущности и устройства реализованы в библиотеке.
PIP также тесно интегрируется с системой сборки [CMake](https://cmake.org/), предоставляя удобный поиск
главной библиотеки, модулей PIP и некоторых утилит. Используя CMake вместе с PIP
можно генерировать и использовать метаинформация о коде или сериализовать
свои типы данных с обратной совместимостью их версий.
Сводку можно найти на странице \ref summary.
Базовое использование PIP описано на странице \ref using_basic.

104
doc/pages/summary.md Normal file
View File

@@ -0,0 +1,104 @@
\~english \page summary Functionality summary
\~russian \page summary Сводка функциональности
\~english
* direct output to console (\a PICout)
* containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* byte array (\a PIByteArray)
* serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
* string (\a PIConstChars, \a PIString, \a PIStringList)
* base object (events and handlers) (\a PIObject)
* multithreading
* thread (\a PIThread)
* blocking (\a PIMutex, \a PISpinlock)
* executor (\a PIThreadPoolExecutor)
* blocking dequeue (\a PIBlockingDequeue)
* timer (\a PITimer)
* tiling console (with widgets) (\a PIScreen)
* simple text rows
* scroll bar
* list
* button
* buttons group
* check box
* progress bar
* PICout output
* text input
* I/O devices
* base class (\a PIIODevice)
* file (\a PIFile)
* serial port (\a PISerial)
* ethernet (\a PIEthernet)
* USB (\a PIUSB)
* packets extractor (\a PIPacketExtractor)
* binary log (\a PIBinaryLog)
* complex I/O point (\a PIConnection)
* peering net node (\a PIPeer)
* connection quality diagnotic (\a PIDiagnostics)
* Run-time libraries
* abstract (\a PILibrary)
* plugin (\a PIPluginLoader)
* Mathematics
* complex numbers
* vectors (\a PIMathVector, \a PIMathVectorT)
* matrices (\a PIMathMatrix, \a PIMathMatrixT)
* quaternion (\a PIQuaternion)
* 2D geometry (\a PIPoint, \a PILine, \a PIRect)
* statistic (\a PIStatistic)
* CRC checksum (\a PICRC)
* Fourier transform (\a PIFFTW, \a PIFFT)
* expression evaluator (\a PIEvaluator)
* command-line arguments parser (\a PICLI)
* process (\a PIProcess)
\~russian
* общение с консолью (\a PICout)
* контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* байтовый массив (\a PIByteArray)
* сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream)
* строка (\a PIConstChars, \a PIString, \a PIStringList)
* базовый объект (события и обработчики) (\a PIObject)
* многопоточность
* поток (\a PIThread)
* блокировки (\a PIMutex, \a PISpinlock)
* исполнитель (\a PIThreadPoolExecutor)
* блокирующая очередь (\a PIBlockingDequeue)
* таймер (\a PITimer)
* тайлинговая консоль (с виджетами) (\a PIScreen)
* простой вывод строк
* скроллбар
* лист
* кнопка
* группа кнопок
* галочка
* прогрессбар
* вывод PICout
* текстовый ввод
* устройства ввода/вывода
* базовый класс (\a PIIODevice)
* файл (\a PIFile)
* последовательный порт (\a PISerial)
* ethernet (\a PIEthernet)
* USB (\a PIUSB)
* packets extractor (\a PIPacketExtractor)
* бинарный логфайл (\a PIBinaryLog)
* сложное составное устройство (\a PIConnection)
* пиринговая сеть (\a PIPeer)
* диагностика качества связи (\a PIDiagnostics)
* поддержка библиотек времени выполнения
* базовая функциональность (\a PILibrary)
* плагин (\a PIPluginLoader)
* Математика
* комплексные числа
* вектора (\a PIMathVector, \a PIMathVectorT)
* матрицы (\a PIMathMatrix, \a PIMathMatrixT)
* кватернион (\a PIQuaternion)
* 2D геометрия (\a PIPoint, \a PILine, \a PIRect)
* статистика (\a PIStatistic)
* CRC контрольная сумма (\a PICRC)
* преобразования Фурье (\a PIFFTW, \a PIFFT)
* вычислитель выражений (\a PIEvaluator)
* парсер аргументов командной строки (\a PICLI)
* процесс (\a PIProcess)

128
doc/pages/using_basic.md Normal file
View File

@@ -0,0 +1,128 @@
\~english \page using_basic Getting started
\~russian \page using_basic Простые начала
\~english
Many novice programmers are solved many common task with system integrity: output to console,
keyboard buttons press detecting, working with serial ports, ethernet or files, and many other.
These tasks can solve this library, and code, based only on PIP will be compile and work
similar on many systems: Windows, any Linux, Red Hat, FreeBSD, MacOS X and QNX.
Typical application on PIP looks like this: \n
\~russian
Многие начинающие программисты решают общие задачи взаимодействия с операционной системой:
вывод в консоль, определение нажатия клавиш, работа с последовательными портами, сетью или файлами,
и многое другое. Эти задачи решены в библиотеке, и код, основанный на PIP будет компилироваться
и работать одинаково на многих системах: Windows, любой Linux, Red Hat, FreeBSD, MacOS X и QNX.
Типовое приложение на PIP выглядит примерно так: \n
\code{.cpp}
#include <pip.h>
// declare key press handler
void key_event(char key, void * );
PIConsole console(false, key_event); // don`t start now, key handler is "key_event"
// some vars
int i = 2, j = 3;
// implicit key press handler
void key_event(char key, void * ) {
switch (key) {
case '-':
i--;
break;
case '+':
i++;
break;
case '(':
j--;
break;
case ')':
j++;
break;
};
};
class MainClass: public PITimer {
PIOBJECT(MainClass)
public:
MainClass() {}
protected:
void tick(void * data, int delimiter) {
piCout << "timer tick";
// timer tick
}
};
MainClass main_class;
int main(int argc, char * argv[]) {
// enabling auto-detection of exit button press, by default 'Q' (shift+q)
console.enableExitCapture();
// if we want to parse command-line arguments
PICLI cli(argc, argv);
cli.addArgument("console"); // "-c" or "--console"
cli.addArgument("debug"); // "-d" or "--debug"
// enabling or disabling global debug flag
piDebug = cli.hasArgument("debug");
// configure console
console.addTab("first tab", '1');
console.addString("PIP console", 1, PIConsole::Bold);
console.addVariable("int var (i)", &i, 1);
console.addVariable("int green var (j)", &j, 1, PIConsole::Green);
console.addString("'-' - i--", 2);
console.addString("'+' - i++", 2);
console.addString("'(' - j--", 2);
console.addString("')' - j++", 2);
console.addTab("second tab", '2');
console.addString("col 1", 1);
console.addString("col 2", 2);
console.addString("col 3", 3);
console.setTab("first tab");
// start output to console if "console" argument exists
if (cli.hasArgument("console"))
console.start();
// start main class, e.g. 40 Hz
main_class.start(25.);
// wait for 'Q' press, independently if console is started or not
console.waitForFinish();
return 0;
};
\endcode
\~english
This code demonstrates simple interactive configurable program, which can be started with console
display or not, and with debug or not. \b MainClass is central class that also can be inherited from
\a PIThread and reimplement \a run() function.
\n Many PIP classes has events and event handlers, which can be connected one to another.
Details you can see at \a PIObject reference page (\ref PIObject_sec0).
\n To configure your program from file use \a PIConfig.
\n If you want more information see \ref using_advanced
\~russian
Этот код демонстрирует простую конфигурируемую программу, которая может быть запущена с
This code demonstrates simple interactive configurable program, which can be started with console
display or not, and with debug or not. \b MainClass is central class that also can be inherited from
\a PIThread and reimplement \a run() function.
\n Many PIP classes has events and event handlers, which can be connected one to another.
Details you can see at \a PIObject reference page (\ref PIObject_sec0).
\n To configure your program from file use \a PIConfig.

BIN
doc/pip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

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

29
library.json Normal file
View File

@@ -0,0 +1,29 @@
{
"name": "PIP",
"keywords": "pip",
"description": "Platform-Independent Primitives",
"repository":
{
"type": "git",
"url": "https://git.shs.tools/SHS/pip.git"
},
"frameworks": "*",
"platforms": "*",
"dependencies": {
"mike-matera/ArduinoSTL": "^1.3.2",
"linlin-study/FreeRTOS-Kernel": ">=10.0.0"
},
"build":
{
"srcFilter": [
"+<libs/main/core/*.cpp>",
"+<libs/main/containers/*.cpp>",
"+<libs/main/math/*.cpp>",
"+<libs/main/thread/*.cpp>",
"+<libs/main/io_uutils/*.cpp>",
"+<libs/main/geo/*.cpp>"
],
"extraScript": "platformio_pre.py",
"flags": "-DPIP_FREERTOS"
}
}

View File

@@ -1,8 +1,8 @@
#include "picloudbase.h"
PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) {
PICloudBase::PICloudBase(): eth(PIEthernet::TCP_Client), streampacker(&eth), tcp(&streampacker) {
eth.setDebug(false);
}

View File

@@ -1,151 +1,191 @@
/*
PIP - Platform Independent Primitives
PICloud Client
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 "picloudclient.h"
#include "picloudtcp.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode), PICloudBase() {
tcp.setRole(PICloud::TCP::Client);
setName("cloud_client");
is_connected = false;
CONNECTL(&eth, connected, [this](){tcp.sendStart();});
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, disconnected, [this](bool){
piCoutObj << "disconnected";
opened_ = false;
is_connected = false;
cond_connect.notifyOne();
cond_buff.notifyOne();
piMSleep(100);
});
}
PICloudClient::~PICloudClient() {
eth.close();
if (is_connected) {
is_connected = false;
disconnected();
cond_buff.notifyOne();
cond_connect.notifyOne();
}
close();
stop();
}
void PICloudClient::setServerName(const PIString & server_name) {
setName("cloud_client__" + server_name);
tcp.setServerName(server_name);
}
void PICloudClient::setKeepConnection(bool on) {
eth.setParameter(PIEthernet::KeepConnection, on);
}
bool PICloudClient::openDevice() {
// piCout << "PICloudClient open device" << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
if (op) {
mutex_buff.lock();
eth.startThreadedRead();
bool conn_ok = cond_connect.waitFor(mutex_buff, (int)eth.readTimeout(), [this](){return isConnected();});
piCoutObj << "conn_ok" << conn_ok;
mutex_buff.unlock();
if (!conn_ok) {
eth.stop();
eth.close();
piMSleep(100);
}
return isConnected();
} else {
eth.close();
return false;
}
}
bool PICloudClient::closeDevice() {
if (is_connected) {
is_connected = false;
disconnected();
cond_buff.notifyOne();
cond_connect.notifyOne();
}
eth.stop();
if (eth.isOpened()) eth.close();
return true;
}
int PICloudClient::readDevice(void * read_to, int max_size) {
// piCoutObj << "readDevice";
if (!is_connected) return -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();});
int sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
mutex_buff.unlock();
return sz;
}
int PICloudClient::writeDevice(const void * data, int size) {
// piCoutObj << "writeDevice";
return tcp.sendData(PIByteArray(data, size));
}
void PICloudClient::_readed(PIByteArray & ba) {
mutex_buff.lock();
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect:
if (tcp.parseConnect(ba) == 1) {
is_connected = true;
connected();
cond_connect.notifyOne();
}
break;
case PICloud::TCP::Disconnect:
is_connected = false;
eth.stop();
eth.close();
disconnected();
break;
case PICloud::TCP::Data:
if (is_connected) {
buff.append(ba);
cond_buff.notifyOne();
}
break;
default:
break;
}
//piCoutObj << "readed" << ba.toHex();
}
mutex_buff.unlock();
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100);
}
/*
PIP - Platform Independent Primitives
PICloud Client
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 "picloudclient.h"
#include "picloudtcp.h"
PICloudClient::PICloudClient(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
tcp.setRole(PICloud::TCP::Client);
setThreadedReadBufferSize(eth.threadedReadBufferSize());
setName("cloud_client");
is_connected = false;
is_deleted = false;
// setReopenEnabled(false);
CONNECTL(&eth, connected, [this]() {
opened_ = true;
tcp.sendStart();
});
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, disconnected, [this](bool) {
if (is_deleted) return;
bool need_disconn = is_connected;
// piCoutObj << "eth disconnected";
eth.stop();
opened_ = false;
internalDisconnect();
if (need_disconn) disconnected();
// piCoutObj << "eth disconnected done";
});
}
PICloudClient::~PICloudClient() {
// piCoutObj << "~PICloudClient() ..." << this;
is_deleted = true;
stopAndWait();
close();
internalDisconnect();
// piCoutObj << "~PICloudClient() done" << this;
}
void PICloudClient::setServerName(const PIString & server_name) {
setName("cloud_client__" + server_name);
tcp.setServerName(server_name);
}
void PICloudClient::setKeepConnection(bool on) {
eth.setParameter(PIEthernet::KeepConnection, on);
}
void PICloudClient::interrupt() {
cond_buff.notifyOne();
cond_connect.notifyOne();
eth.interrupt();
}
bool PICloudClient::openDevice() {
// piCoutObj << "open";// << path();
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) {
mutex_connect.lock();
eth.startThreadedRead();
// piCoutObj << "connecting...";
bool conn_ok = cond_connect.waitFor(mutex_connect, (int)eth.readTimeout());
// piCoutObj << "conn_ok" << conn_ok << is_connected;
mutex_connect.unlock();
if (!conn_ok) {
mutex_connect.lock();
eth.stopAndWait();
eth.close();
mutex_connect.unlock();
}
return is_connected;
} else {
// eth.close();
return false;
}
}
bool PICloudClient::closeDevice() {
// PIThread::stop();
if (is_connected) {
internalDisconnect();
}
eth.stopAndWait();
eth.close();
return true;
}
ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) {
if (is_deleted || max_size <= 0) return -1;
// piCoutObj << "readDevice ...";
if (!is_connected && eth.isClosed()) openDevice();
ssize_t sz = -1;
mutex_buff.lock();
if (is_connected) {
if (buff.isEmpty()) {
sz = 0;
} else {
sz = piMin<ssize_t>(max_size, buff.size_s());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
}
if (sz == 0) cond_buff.wait(mutex_buff);
}
mutex_buff.unlock();
if (!is_connected) opened_ = false;
// piCoutObj << "readDevice done" << sz;
return sz;
}
ssize_t PICloudClient::writeDevice(const void * data, ssize_t size) {
if (is_deleted || !is_connected) return -1;
// piCoutObj << "writeDevice" << size;
return tcp.sendData(PIByteArray(data, size));
}
void PICloudClient::internalDisconnect() {
// piCoutObj << "internalDisconnect";
is_connected = false;
cond_buff.notifyOne();
cond_connect.notifyOne();
streampacker.clear();
buff.clear();
}
void PICloudClient::_readed(PIByteArray & ba) {
if (is_deleted) return;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
// piCoutObj << "_readed" << ba.size() << hdr.first << hdr.second;
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect:
if (tcp.parseConnect(ba) == 1) {
mutex_connect.lock();
is_connected = true;
mutex_connect.unlock();
cond_connect.notifyOne();
connected();
}
break;
case PICloud::TCP::Disconnect:
eth.stop();
opened_ = false;
eth.close();
break;
case PICloud::TCP::Data:
if (is_connected) {
mutex_buff.lock();
if (buff.size_s() > threadedReadBufferSize()) {
piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes";
mutex_buff.unlock();
return;
}
buff.append(ba);
mutex_buff.unlock();
cond_buff.notifyOne();
}
break;
default: break;
}
// piCoutObj << "readed" << ba.toHex();
}
// piCoutObj << "_readed done";
}

View File

@@ -1,225 +1,298 @@
/*
PIP - Platform Independent Primitives
PICloud Server
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 "picloudserver.h"
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode) : PIIODevice(path, mode), PICloudBase() {
PIString server_name = "PCS_" + PIString::fromNumber(randomi()%1000);
tcp.setRole(PICloud::TCP::Server);
tcp.setServerName(server_name);
setName("cloud_server__" + server_name);
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, connected, [this](){tcp.sendStart();});
CONNECTL(&eth, disconnected, [this](bool){
piCoutObj << "disconnected";
opened_ = false;
piMSleep(100);
});
}
PICloudServer::~PICloudServer() {
stop();
close();
}
void PICloudServer::setServerName(const PIString & server_name) {
setName("cloud_server__" + server_name);
tcp.setServerName(server_name);
}
PIVector<PICloudServer::Client *> PICloudServer::clients() const {
PIMutexLocker _ml(clients_mutex);
return clients_;
}
bool PICloudServer::openDevice() {
piCout << "PICloudServer open device" << path();
bool op = eth.connect(PIEthernet::Address::resolve(path()), false);
if (op) {
eth.startThreadedRead();
return true;
}
eth.close();
return false;
}
bool PICloudServer::closeDevice() {
eth.stop();
clients_mutex.lock();
for (auto c : clients_) {
c->close();
c->stop();
}
clients_mutex.unlock();
eth.close();
for (auto c : clients_)
delete c;
return true;
}
int PICloudServer::readDevice(void * read_to, int max_size) {
//piCoutObj << "readDevice";
piMSleep(eth.readTimeout());
return -1;
}
int PICloudServer::writeDevice(const void * data, int max_size) {
//piCoutObj << "writeDevice";
return -1;
}
void PICloudServer::clientDisconnect(uint client_id) {
tcp.sendDisconnected(client_id);
}
int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
return tcp.sendData(data, client_id);
}
PICloudServer::Client::Client(PICloudServer * srv, uint id) : server(srv), client_id(id) {
setMode(PIIODevice::ReadWrite);
setReopenEnabled(false);
is_connected = true;
}
PICloudServer::Client::~Client() {
if (is_connected) {
is_connected = false;
cond_buff.notifyOne();
}
close();
stop();
}
bool PICloudServer::Client::openDevice() {
return is_connected;
}
bool PICloudServer::Client::closeDevice() {
if (is_connected) {
server->clientDisconnect(client_id);
is_connected = false;
cond_buff.notifyOne();
}
return true;
}
int PICloudServer::Client::readDevice(void * read_to, int max_size) {
if (!is_connected) return -1;
mutex_buff.lock();
cond_buff.wait(mutex_buff, [this](){return !buff.isEmpty();});
int sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
mutex_buff.unlock();
return sz;
}
int PICloudServer::Client::writeDevice(const void * data, int size) {
return server->sendData(PIByteArray(data, size), client_id);
}
void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
if (!is_connected) return;
mutex_buff.lock();
buff.append(ba);
cond_buff.notifyOne();
mutex_buff.unlock();
while (buff.size_s() > threadedReadBufferSize()) piMSleep(100);
}
void PICloudServer::_readed(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect: {
uint id = tcp.parseConnect(ba);
clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock();
if (oc) {
tcp.sendDisconnected(id);
} else {
piCoutObj << "new Client" << id;
Client * c = new Client(this, id);
CONNECTU(c, deleted, this, clientDeleted);
clients_mutex.lock();
clients_ << c;
index_clients.insert(id, c);
clients_mutex.unlock();
newConnection(c);
}
} break;
case PICloud::TCP::Disconnect: {
uint id = tcp.parseDisconnect(ba);
piCoutObj << "remove Client" << id;
clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock();
if (oc) {
oc->is_connected = false;
oc->close();
}
} break;
case PICloud::TCP::Data: {
PIPair<uint, PIByteArray> d = tcp.parseDataServer(ba);
clients_mutex.lock();
Client * oc = index_clients.value(d.first, nullptr);
clients_mutex.unlock();
//piCoutObj << "data for" << d.first << d.second.toHex();
if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} break;
default: break;
}
}
}
void PICloudServer::clientDeleted(PIObject * o) {
PICloudServer::Client * c = (PICloudServer::Client*)o;
clients_mutex.lock();
clients_.removeOne(c);
auto it = index_clients.makeIterator();
while (it.hasNext()) {
it.next();
if (it.value() == c) {
index_clients.remove(it.key());
break;
}
}
clients_mutex.unlock();
}
/*
PIP - Platform Independent Primitives
PICloud Server
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 "picloudserver.h"
PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode): PIIODevice(path, mode), PICloudBase() {
PIString server_name = "PCS_" + PIString::fromNumber(randomi() % 1000);
tcp.setRole(PICloud::TCP::Server);
tcp.setServerName(server_name);
setName("cloud_server__" + server_name);
is_deleted = false;
eth.setReopenEnabled(false);
setThreadedReadBufferSize(eth.threadedReadBufferSize());
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
CONNECTL(&eth, connected, [this]() {
open_mutex.lock();
opened_ = true;
cvar.notifyOne();
open_mutex.unlock();
piCoutObj << "connected";
tcp.sendStart();
});
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();
});
CONNECTL(&ping_timer, tickEvent, [this](void *, int) {
if (eth.isConnected()) tcp.sendPing();
});
}
PICloudServer::~PICloudServer() {
// piCoutObj << "~PICloudServer ..." << this;
is_deleted = true;
stop();
close();
waitThreadedReadFinished();
// piCout << "wait";
while (removed_clients_.isNotEmpty()) {
Client * c = removed_clients_.take_back();
delete c;
}
// piCoutObj << "~PICloudServer done" << this;
}
void PICloudServer::setServerName(const PIString & server_name) {
setName("cloud_server__" + server_name);
tcp.setServerName(server_name);
}
PIVector<PICloudServer::Client *> PICloudServer::clients() const {
PIMutexLocker _ml(clients_mutex);
return clients_;
}
bool PICloudServer::openDevice() {
piCoutObj << "open device" << path();
if (is_deleted) return false;
bool op = eth.connect(PINetworkAddress::resolve(path()), false);
if (op) {
eth.startThreadedRead();
ping_timer.start(5000);
return true;
} else {
ping_timer.stop();
eth.close();
return false;
}
}
bool PICloudServer::closeDevice() {
// piCoutObj << "closeDevice" << this;
eth.stopAndWait();
ping_timer.stop();
eth.close();
cvar.notifyOne();
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();
return true;
}
ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) {
if (is_deleted) return -1;
// piCoutObj << "readDevice";
open_mutex.lock();
if (isOpened()) cvar.wait(open_mutex);
open_mutex.unlock();
// piCoutObj << "opened_ = " << opened_;
// else piMSleep(eth.readTimeout());
return -1;
}
ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) {
// piCoutObj << "writeDevice";
return -1;
}
void PICloudServer::interrupt() {
eth.interrupt();
cvar.notifyOne();
}
void PICloudServer::clientDisconnect(uint client_id) {
tcp.sendDisconnected(client_id);
}
int PICloudServer::sendData(const PIByteArray & data, uint client_id) {
if (!opened_) return -1;
return tcp.sendData(data, client_id);
}
PICloudServer::Client::Client(PICloudServer * srv, uint id): server(srv), client_id(id) {
setMode(PIIODevice::ReadWrite);
setReopenEnabled(false);
setThreadedReadBufferSize(server->threadedReadBufferSize());
is_connected = true;
}
PICloudServer::Client::~Client() {
// piCoutObj << "~PICloudServer::Client..." << this;
close();
stopAndWait();
// piCoutObj << "~PICloudServer::Client done" << this;
}
bool PICloudServer::Client::openDevice() {
return is_connected;
}
bool PICloudServer::Client::closeDevice() {
// piCoutObj << "closeDevice" << this;
if (is_connected) {
server->clientDisconnect(client_id);
is_connected = false;
}
cond_buff.notifyOne();
return true;
}
ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) {
if (!is_connected) return -1;
ssize_t sz = -1;
mutex_buff.lock();
if (is_connected) {
if (buff.isEmpty()) {
sz = 0;
} else {
sz = piMini(max_size, buff.size());
memcpy(read_to, buff.data(), sz);
buff.remove(0, sz);
}
if (sz == 0) cond_buff.wait(mutex_buff);
}
mutex_buff.unlock();
return sz;
}
ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) {
if (!is_connected) return -1;
return server->sendData(PIByteArray(data, size), client_id);
}
void PICloudServer::Client::interrupt() {
cond_buff.notifyOne();
}
void PICloudServer::Client::pushBuffer(const PIByteArray & ba) {
if (!is_connected) return;
mutex_buff.lock();
if (buff.size_s() > threadedReadBufferSize()) {
piCoutObj << "Error: buffer overflow, drop" << ba.size() << "bytes";
mutex_buff.unlock();
return;
}
buff.append(ba);
cond_buff.notifyOne();
mutex_buff.unlock();
}
void PICloudServer::_readed(PIByteArray & ba) {
if (is_deleted) return;
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> hdr = tcp.parseHeader(ba);
if (hdr.second == tcp.role()) {
switch (hdr.first) {
case PICloud::TCP::Connect: {
uint id = tcp.parseConnect(ba);
clients_mutex.lock();
Client * oc = index_clients.value(id, nullptr);
clients_mutex.unlock();
if (oc) {
piCoutObj << "Warning: reject client with duplicated ID";
tcp.sendDisconnected(id);
} else {
Client * c = new Client(this, id);
// piCoutObj << "new Client" << id << c;
CONNECT1(void, PIObject *, c, deleted, this, clientDeleted);
clients_mutex.lock();
clients_ << c;
index_clients.insert(id, c);
clients_mutex.unlock();
newConnection(c);
}
} break;
case PICloud::TCP::Disconnect: {
uint id = tcp.parseDisconnect(ba);
// piCoutObj << "Close on logic";
clients_mutex.lock();
Client * oc = index_clients.take(id, nullptr);
clients_.removeOne(oc);
clients_mutex.unlock();
if (oc) {
oc->stopAndWait();
oc->is_connected = false;
oc->close();
removed_clients_ << oc;
// delete oc;
}
} break;
case PICloud::TCP::Data: {
PIPair<uint, PIByteArray> d = tcp.parseDataServer(ba);
clients_mutex.lock();
Client * oc = index_clients.value(d.first, nullptr);
clients_mutex.unlock();
// piCoutObj << "data for" << d.first << d.second.size();
if (oc && !d.second.isEmpty()) oc->pushBuffer(d.second);
} break;
default: break;
}
}
}
void PICloudServer::clientDeleted(PIObject * o) {
PICloudServer::Client * c = (PICloudServer::Client *)o;
// piCoutObj << "clientDeleted" << c;
clients_mutex.lock();
clients_.removeOne(c);
removed_clients_.removeAll(c);
index_clients.removeWhere([c](uint, Client * v) { return v == c; });
clients_mutex.unlock();
}

View File

@@ -1,163 +1,184 @@
/*
PIP - Platform Independent Primitives
PICloud TCP transport
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 "picloudtcp.h"
#include "picrypt.h"
#include "pichunkstream.h"
#include "piethernet.h"
#include "pistreampacker.h"
const char hash_def_key[] = "_picrypt_";
PICloud::TCP::Header::Header() {
version = Version_2;
}
PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) {
}
void PICloud::TCP::setRole(PICloud::TCP::Role r) {
header.role = r;
}
void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_;
suuid = PICrypt::hash(server_name_);
}
PIString PICloud::TCP::serverName() const {
return server_name;
}
void PICloud::TCP::sendStart() {
//piCout << "sendStart";
if (suuid.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, server not set, invoke setServerName first";
return;
}
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header;
ba.append(suuid);
streampacker->send(ba);
}
void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header << client_id;
streampacker->send(ba);
}
void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect;
PIByteArray ba;
ba << header << client_id;
streampacker->send(ba);
}
int PICloud::TCP::sendData(const PIByteArray & data) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
ba << header;
ba.append(data);
// piCout << "sendData" << ba.toHex();
streampacker->send(ba);
return data.size_s();
}
int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
ba << header << client_id;
ba.append(data);
streampacker->send(ba);
return data.size_s();
}
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret;
ret.first = InvalidType;
ret.second = InvalidRole;
if (ba.size() < sizeof(Header)) return ret;
PICloud::TCP::Header hdr;
ba >> hdr;
if (hdr.version != header.version) {
piCout << "[PICloud]" << "invalid PICloud::TCP version!";
return ret;
}
ret.first = (Type)hdr.type;
ret.second = (Role)hdr.role;
return ret;
}
PIByteArray PICloud::TCP::parseData(PIByteArray & ba) {
if (header.role == Client) {
return ba;
}
return PIByteArray();
}
PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) {
PIPair<uint, PIByteArray> ret;
ret.first = 0;
if (header.role == Server) {
ba >> ret.first;
ret.second = ba;
}
return ret;
}
PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
if (ba.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, invalid server uuid";
return PIByteArray();
} else {
return ba;
}
}
uint PICloud::TCP::parseConnect(PIByteArray & ba) {
uint ret;
ba >> ret;
return ret;
}
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
uint ret;
ba >> ret;
return ret;
}
/*
PIP - Platform Independent Primitives
PICloud TCP transport
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 "picloudtcp.h"
#include "pichunkstream.h"
#include "picrypt.h"
#include "piethernet.h"
#include "pistreampacker.h"
const char hash_cloud_key[] = "_picloud_";
PICloud::TCP::Header::Header() {
version = Version_2;
}
PICloud::TCP::TCP(PIStreamPacker * s): streampacker(s) {
streampacker->setMaxPacketSize(63 * 1024);
}
void PICloud::TCP::setRole(PICloud::TCP::Role r) {
header.role = r;
}
void PICloud::TCP::setServerName(const PIString & 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));
}
PIString PICloud::TCP::serverName() const {
return server_name;
}
void PICloud::TCP::sendStart() {
// piCout << "sendStart";
if (suuid.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, server not set, invoke setServerName first";
return;
}
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header;
ba.append(suuid);
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
}
void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header << client_id;
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
}
void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect;
PIByteArray ba;
ba << header << client_id;
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
}
int PICloud::TCP::sendData(const PIByteArray & data) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
ba << header;
ba.append(data);
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
mutex_send.lock();
streampacker->send(ba);
mutex_send.unlock();
return data.size_s();
}
int PICloud::TCP::sendData(const PIByteArray & data, uint client_id) {
header.type = PICloud::TCP::Data;
PIByteArray ba;
ba << header << client_id;
ba.append(data);
mutex_send.lock();
streampacker->send(ba);
mutex_send.unlock();
return data.size_s();
}
void PICloud::TCP::sendPing() {
header.type = PICloud::TCP::Ping;
PIByteArray ba;
ba << header;
ba.append(suuid);
mutex_send.lock();
streampacker->send(ba);
mutex_send.unlock();
}
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteArray & ba) {
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> ret;
ret.first = InvalidType;
ret.second = InvalidRole;
if (ba.size() < sizeof(Header)) return ret;
PICloud::TCP::Header hdr;
ba >> hdr;
if (hdr.version != header.version) {
piCout << "[PICloud]"
<< "invalid PICloud::TCP version!";
return ret;
}
ret.first = (Type)hdr.type;
ret.second = (Role)hdr.role;
return ret;
}
bool PICloud::TCP::canParseData(PIByteArray & ba) {
return header.role == Client;
}
PIPair<uint, PIByteArray> PICloud::TCP::parseDataServer(PIByteArray & ba) {
PIPair<uint, PIByteArray> ret;
ret.first = 0;
if (header.role == Server) {
ba >> ret.first;
ret.second.swap(ba);
}
return ret;
}
PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
if (ba.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, invalid server uuid";
return PIByteArray();
} else {
return ba;
}
}
uint PICloud::TCP::parseConnect(PIByteArray & ba) {
uint ret = 0;
ba >> ret;
return ret;
}
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
uint ret = 0;
ba >> ret;
return ret;
}

View File

@@ -1,76 +1,81 @@
/*
PIP - Platform Independent Primitives
Compress class using zlib
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 "picompress.h"
#ifdef PIP_COMPRESS
# ifdef FREERTOS
# include "esp32/rom/miniz.h"
# define compress2 mz_compress2
# define Z_OK MZ_OK
# define uncompress mz_uncompress
# else
# include <zlib.h>
# endif
#endif
PIByteArray piCompress(const PIByteArray & ba, int level) {
#ifdef PIP_COMPRESS
PIByteArray zba;
zba.resize(ba.size() + 128);
int ret = 0;
ulong sz = zba.size();
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
if (ret != Z_OK) {
piCout << "[PICompress]" << "Error: invalid input or not enought memory";
return ba;
}
zba.resize(sz);
zba << ullong(ba.size());
return zba;
#else
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return ba;
}
PIByteArray piDecompress(const PIByteArray & zba) {
#ifdef PIP_COMPRESS
ullong sz;
if (zba.size() < sizeof(ullong)) {
piCout << "[PICompress]" << "Error: invalid input";
return zba;
}
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
ba >> sz;
ba.resize(sz);
int ret = 0;
ulong s = sz;
ret = uncompress(ba.data(), &s, zba.data(), zba.size());
if (ret != Z_OK) {
piCout << "[PICompress]" << "Error: invalid input or not enought memory";
return zba;
}
return ba;
#else
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return zba;
}
/*
PIP - Platform Independent Primitives
Compress class using zlib
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 "picompress.h"
#ifdef PIP_COMPRESS
# ifdef ESP_PLATFORM
# include "esp32/rom/miniz.h"
# define compress2 mz_compress2
# define Z_OK MZ_OK
# define uncompress mz_uncompress
# else
# include <zlib.h>
# endif
#endif
PIByteArray piCompress(const PIByteArray & ba, int level) {
#ifdef PIP_COMPRESS
PIByteArray zba;
zba.resize(ba.size() + 128);
int ret = 0;
ulong sz = zba.size();
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory";
return ba;
}
zba.resize(sz);
zba << ullong(ba.size());
return zba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return ba;
}
PIByteArray piDecompress(const PIByteArray & zba) {
#ifdef PIP_COMPRESS
ullong sz = 0;
if (zba.size() < sizeof(ullong)) {
piCout << "[PICompress]"
<< "Error: invalid input";
return zba;
}
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
ba >> sz;
ba.resize(sz);
int ret = 0;
ulong s = sz;
ret = uncompress(ba.data(), &s, zba.data(), zba.size());
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory";
return zba;
}
return ba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return zba;
}

View File

@@ -1,31 +1,33 @@
/*
PIP - Platform Independent Primitives
Console output/input
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Console output/input
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 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.
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/>.
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 "piscreen.h"
#include "piincludes_p.h"
#ifndef WINDOWS
# include <sys/ioctl.h>
# include <fcntl.h>
# include <sys/ioctl.h>
# include <termios.h>
#else
# include <wincon.h>
# include <wingdi.h>
# ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000
# define COMMON_LVB_UNDERSCORE 0x8000
# endif
#endif
@@ -50,29 +52,6 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
PIScreen::SystemConsole::SystemConsole() {
width = height = pwidth = pheight = 0;
mouse_x = mouse_y = -1;
int w, h;
#ifdef WINDOWS
PRIVATE->ulcoord.X = 0;
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
# ifdef FREERTOS
w = 80;
h = 24;
# else
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
h = ws.ws_row;
# endif
#endif
resize(w, h);
}
@@ -85,6 +64,29 @@ PIScreen::SystemConsole::~SystemConsole() {
void PIScreen::SystemConsole::begin() {
int w, h;
#ifdef WINDOWS
PRIVATE->ulcoord.X = 0;
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
# ifdef MICRO_PIP
w = 80;
h = 24;
# else
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
h = ws.ws_row;
# endif
#endif
resize(w, h);
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -92,6 +94,7 @@ void PIScreen::SystemConsole::begin() {
PRIVATE->bc.Y = 0;
#endif
clear();
clearScreen();
hideCursor();
}
@@ -108,16 +111,13 @@ void PIScreen::SystemConsole::end() {
void PIScreen::SystemConsole::prepare() {
int w, h;
int w = 80, h = 24;
#ifdef WINDOWS
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1;
h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1;
#else
# ifdef FREERTOS
w = 80;
h = 24;
# else
# ifndef MICRO_PIP
winsize ws;
ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col;
@@ -136,15 +136,15 @@ void PIScreen::SystemConsole::clear() {
void PIScreen::SystemConsole::resize(int w, int h) {
if (w == pwidth && h == pheight) return;
width = piMaxi(w, 0);
height = piMaxi(h, 0);
pwidth = width;
width = piMaxi(w, 0);
height = piMaxi(h, 0);
pwidth = width;
pheight = height;
cells.resize(height);
pcells.resize(height);
for (int i = 0; i < height; ++i) {
cells[i].resize(width);
pcells[i].resize(width, Cell(0));
pcells[i].resize(width, Cell(PIChar()));
}
#ifdef WINDOWS
PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow;
@@ -159,7 +159,7 @@ void PIScreen::SystemConsole::resize(int w, int h) {
void PIScreen::SystemConsole::print() {
if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) {
///cells[mouse_y][mouse_x].format.flags ^= Inverse;
/// cells[mouse_y][mouse_x].format.flags ^= Inverse;
}
#ifdef WINDOWS
PRIVATE->srect = PRIVATE->sbi.srWindow;
@@ -187,10 +187,10 @@ void PIScreen::SystemConsole::print() {
int k = j * dw + i;
Cell & c(cells[j + dy0][i + dx0]);
PRIVATE->chars[k].Char.UnicodeChar = 0;
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
PRIVATE->chars[k].Attributes = attributes(c);
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
PRIVATE->chars[k].Attributes = attributes(c);
}
//piCout << "draw" << dw << dh;
// piCout << "draw" << dw << dh;
PRIVATE->bs.X = dw;
PRIVATE->bs.Y = dh;
PRIVATE->srect.Left += dx0;
@@ -221,14 +221,15 @@ void PIScreen::SystemConsole::print() {
} else {
if (!s.isEmpty()) {
moveTo(si, sj);
printf("%s", s.data());
PICout::stdoutPIString(s);
s.clear();
}
}
}
if (!s.isEmpty()) {
moveTo(si, sj);
printf("%s", s.data());
PICout::stdoutPIString(s);
// printf("%s", s.data());
s.clear();
}
}
@@ -240,33 +241,37 @@ void PIScreen::SystemConsole::print() {
#ifdef WINDOWS
#define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
# define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
# define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr;
if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY;
else attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE;
else attr &= ~COMMON_LVB_UNDERSCORE;
if (c.format.flags & Bold)
attr |= FOREGROUND_INTENSITY;
else
attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline)
attr |= COMMON_LVB_UNDERSCORE;
else
attr &= ~COMMON_LVB_UNDERSCORE;
switch (c.format.color_char) {
case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break;
case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break;
case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break;
case Blue: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_BLUE; break;
case Cyan: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
case Magenta: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_BLUE; break;
case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case White: attr = attr | FOREGROUND_MASK; break;
case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break;
case White: attr = attr | FOREGROUND_MASK; break;
}
switch (c.format.color_back) {
case Black: attr = (attr & ~BACKGROUND_MASK); break;
case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break;
case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break;
case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break;
case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case Black: attr = (attr & ~BACKGROUND_MASK); break;
case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break;
case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break;
case Blue: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_BLUE; break;
case Cyan: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
case Magenta: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_BLUE; break;
case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case White: attr = attr | BACKGROUND_MASK; break;
case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break;
case White: attr = attr | BACKGROUND_MASK; break;
}
if ((c.format.flags & Inverse) == Inverse) {
uchar f = attr & 0xFF;
@@ -276,8 +281,8 @@ ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
}
return attr;
}
#undef FOREGROUND_MASK
#undef BACKGROUND_MASK
# undef FOREGROUND_MASK
# undef BACKGROUND_MASK
void PIScreen::SystemConsole::getWinCurCoord() {
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
@@ -292,37 +297,38 @@ void PIScreen::SystemConsole::clearLine() {
void PIScreen::SystemConsole::newLine() {
getWinCurCoord();
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
PRIVATE->ccoord.X = 0;
PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
}
#else // WINDOWS
#else // WINDOWS
PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) {
PIString ts("\e[0");
PIString ts = PIStringAscii("\e[0");
switch (c.format.color_char) {
case Black: ts += ";30"; break;
case Red: ts += ";31"; break;
case Green: ts += ";32"; break;
case Blue: ts += ";34"; break;
case Cyan: ts += ";36"; break;
case Magenta: ts += ";35"; break;
case Yellow: ts += ";33"; break;
case White: ts += ";37"; break;
case Black: ts += PIStringAscii(";30"); break;
case Red: ts += PIStringAscii(";31"); break;
case Green: ts += PIStringAscii(";32"); break;
case Blue: ts += PIStringAscii(";34"); break;
case Cyan: ts += PIStringAscii(";36"); break;
case Magenta: ts += PIStringAscii(";35"); break;
case Yellow: ts += PIStringAscii(";33"); break;
case White: ts += PIStringAscii(";37"); break;
}
switch (c.format.color_back) {
case Black: ts += ";40"; break;
case Red: ts += ";41"; break;
case Green: ts += ";42"; break;
case Blue: ts += ";44"; break;
case Cyan: ts += ";46"; break;
case Magenta: ts += ";45"; break;
case Yellow: ts += ";43"; break;
case White: ts += ";47"; break;
case Black: ts += PIStringAscii(";40"); break;
case Red: ts += PIStringAscii(";41"); break;
case Green: ts += PIStringAscii(";42"); break;
case Blue: ts += PIStringAscii(";44"); break;
case Cyan: ts += PIStringAscii(";46"); break;
case Magenta: ts += PIStringAscii(";45"); break;
case Yellow: ts += PIStringAscii(";43"); break;
case White: ts += PIStringAscii(";47"); break;
}
if ((c.format.flags & Bold) == Bold) ts += ";1";
if ((c.format.flags & Underline) == Underline) ts += ";4";
if ((c.format.flags & Blink) == Blink) ts += ";5";
if ((c.format.flags & Inverse) == Inverse) ts += ";7";
return ts + "m";
if ((c.format.flags & Bold) == Bold) ts += PIStringAscii(";1");
if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4");
if ((c.format.flags & Blink) == Blink) ts += PIStringAscii(";5");
if ((c.format.flags & Inverse) == Inverse) ts += PIStringAscii(";7");
return ts + 'm';
}
#endif // WINDOWS
@@ -358,8 +364,16 @@ void PIScreen::SystemConsole::clearScreen() {
void PIScreen::SystemConsole::clearScreenLower() {
#ifdef WINDOWS
getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut, 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);
FillConsoleOutputAttribute(PRIVATE->hOut,
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
printf("\e[0m\e[J");
#endif
@@ -384,26 +398,25 @@ void PIScreen::SystemConsole::showCursor() {
}
// PIScreen
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen");
setPriority(piLow);
needLockRun(true);
mouse_ = false;
ret_func = slot;
tile_focus = tile_dialog = 0;
root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow);
CONNECTU(listener, mouseEvent, this, mouse_event);
CONNECTU(listener, wheelEvent, this, wheel_event);
mouse_ = false;
ret_func = slot;
tile_focus = tile_dialog = nullptr;
root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow);
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event);
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event);
if (startNow) start();
}
PIScreen::~PIScreen() {
if (isRunning())
stop();
if (isRunning()) stop();
PIThread::waitForFinish(10);
listener->waitForFinish(10);
delete listener;
@@ -411,7 +424,7 @@ PIScreen::~PIScreen() {
void PIScreen::setMouseEnabled(bool on) {
mouse_ = on;
mouse_ = on;
console.mouse_x = console.mouse_y = -1;
}
@@ -423,14 +436,12 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
return;
*/
PIScreenTile * rtile = rootTile();
if (tile_dialog)
rtile = tile_dialog;
if (tile_dialog) rtile = tile_dialog;
bool used = nextFocus(rtile, key);
if (used) return;
if (!used && tile_focus) {
if (tile_focus->visible) {
if (tile_focus->keyEvent(key))
return;
if (tile_focus->keyEvent(key)) return;
}
}
if (ret_func != 0) ret_func(key, data_);
@@ -438,14 +449,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
}
PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile * > ret;
PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile *> ret;
if (!mouse_ || !e) return ret;
console.mouse_x = e->x;
console.mouse_y = e->y;
PIVector<PIScreenTile * > tl = tilesUnderMouse(e->x, e->y);
bool ff = false;
piForeachR (PIScreenTile * t, tl) {
console.mouse_x = e->x;
console.mouse_y = e->y;
PIVector<PIScreenTile *> tl = tilesUnderMouse(e->x, e->y);
bool ff = false;
piForeachR(PIScreenTile * t, tl) {
if (!ff) {
if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) {
t->setFocus();
@@ -456,20 +467,19 @@ PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e)
ff = true;
}
}
}
return tl;
}
PIVector<PIScreenTile * > PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile * > ret;
PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile *> ret;
if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret;
PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile();
bool f = true;
bool f = true;
while (ct) {
if (!f) ret << ct;
f = false;
f = false;
ct = ct->childUnderMouse(x, y);
}
return ret;
@@ -477,27 +487,25 @@ PIVector<PIScreenTile * > PIScreen::tilesUnderMouse(int x, int y) {
void PIScreen::mouse_event(PIKbdListener::MouseEvent me) {
PIVector<PIScreenTile * > tl = prepareMouse(&me);
PIVector<PIScreenTile *> tl = prepareMouse(&me);
if (tl.isEmpty()) return;
piForeachR (PIScreenTile * t, tl)
piForeachR(PIScreenTile * t, tl)
if (t->mouseEvent(me)) break;
}
void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
PIVector<PIScreenTile * > tl = prepareMouse(&we);
PIVector<PIScreenTile *> tl = prepareMouse(&we);
if (tl.isEmpty()) return;
piForeachR (PIScreenTile * t, tl)
piForeachR(PIScreenTile * t, tl)
if (t->wheelEvent(we)) break;
}
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile*> vtl = rt->children(true), ftl;
piForeach (PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus])
ftl << t;
PIVector<PIScreenTile *> vtl = rt->children(true), ftl;
piForeach(PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus]) ftl << t;
}
int ind = -1;
for (int i = 0; i < ftl.size_s(); ++i)
@@ -505,18 +513,15 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
ind = i;
break;
}
if (ind < 0)
tile_focus = 0;
if (ind < 0) tile_focus = 0;
if (ftl.isEmpty())
tile_focus = 0;
else {
if (tile_focus)
if (!tile_focus->visible)
tile_focus = 0;
if (!tile_focus->visible) tile_focus = 0;
int next = tile_focus ? 0 : 1;
if (tile_focus) {
if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab)
next = 1;
if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) next = 1;
if (tile_focus->focus_flags[NextByArrowsHorizontal]) {
if (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1;
@@ -526,16 +531,16 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
if (key.key == PIKbdListener::DownArrow) next = 1;
}
}
//piCout << ftl.size() << ind << next;
// piCout << ftl.size() << ind << next;
if (next != 0) {
PIVector<PIScreenTile*> tl = rt->children();
piForeach (PIScreenTile * t, tl)
PIVector<PIScreenTile *> tl = rt->children();
piForeach(PIScreenTile * t, tl)
t->has_focus = false;
if (!ftl.isEmpty()) {
ind += next;
if (ind >= ftl.size_s()) ind = 0;
if (ind < 0) ind = ftl.size_s() - 1;
tile_focus = ftl[ind];
tile_focus = ftl[ind];
tile_focus->has_focus = true;
}
return true;
@@ -551,22 +556,19 @@ void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
void PIScreen::tileRemovedInternal(PIScreenTile * t) {
if (tile_dialog == t)
tile_dialog = 0;
if (tile_dialog == t) tile_dialog = 0;
}
void PIScreen::tileSetFocusInternal(PIScreenTile * t) {
PIScreenTile * rt = rootTile();
if (tile_dialog)
rt = tile_dialog;
PIVector<PIScreenTile*> tl = rt->children(), ftl;
piForeach (PIScreenTile * i, tl)
if (tile_dialog) rt = tile_dialog;
PIVector<PIScreenTile *> tl = rt->children(), ftl;
piForeach(PIScreenTile * i, tl)
i->has_focus = false;
tile_focus = t;
if (!tile_focus) return;
if (tile_focus->focus_flags[CanHasFocus])
tile_focus->has_focus = true;
if (tile_focus->focus_flags[CanHasFocus]) tile_focus->has_focus = true;
}
@@ -589,7 +591,7 @@ void PIScreen::waitForFinish() {
void PIScreen::stop(bool clear) {
PIThread::stop(true);
PIThread::stopAndWait();
if (clear) console.clearScreen();
#ifndef WINDOWS
fflush(0);
@@ -613,16 +615,21 @@ void PIScreen::run() {
if (tile_dialog) {
int sw(0), sh(0);
tile_dialog->sizeHint(sw, sh);
sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth);
sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight);
tile_dialog->x_ = (console.width - sw) / 2;
tile_dialog->y_ = (console.height - sh) / 2;
tile_dialog->width_ = sw;
sw = piClampi(sw, tile_dialog->minimumWidth, tile_dialog->maximumWidth);
sh = piClampi(sh, tile_dialog->minimumHeight, tile_dialog->maximumHeight);
tile_dialog->x_ = (console.width - sw) / 2;
tile_dialog->y_ = (console.height - sh) / 2;
tile_dialog->width_ = sw;
tile_dialog->height_ = sh;
tile_dialog->layout();
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,
(Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags);
drawer_.drawFrame(dx,
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_);
}
console.print();
@@ -636,10 +643,8 @@ void PIScreen::end() {
PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile*> tl(tiles());
piForeach (PIScreenTile * t, tl)
if (t->name() == name)
return t;
PIVector<PIScreenTile *> tl(tiles());
piForeach(PIScreenTile * t, tl)
if (t->name() == name) return t;
return 0;
}

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API
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 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.
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/>.
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 "piscreenconsole.h"
@@ -22,21 +22,14 @@
using namespace PIScreenTypes;
TileVars::TileVars(const PIString &n) : PIScreenTile(n) {
TileVars::TileVars(const PIString & n): PIScreenTile(n) {
alignment = Left;
}
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

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
Console output/input
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Console output/input
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 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.
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/>.
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 "piscreendrawer.h"
@@ -25,68 +25,68 @@
using namespace PIScreenTypes;
PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell> > & c): cells(c) {
PIScreenDrawer::PIScreenDrawer(PIVector<PIVector<Cell>> & c): cells(c) {
arts_[LineVertical] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('|');
PIChar('|');
#endif
arts_[LineHorizontal] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('-');
PIChar('-');
#endif
arts_[Cross] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerTopLeft] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerTopRight] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerBottomLeft] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[CornerBottomRight] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('+');
PIChar('+');
#endif
arts_[Unchecked] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('O');
PIChar('O');
#endif
arts_[Checked] =
#ifdef USE_UNICODE
PIChar::fromUTF8("");
PIChar::fromUTF8("");
#else
PIChar('0');
PIChar('0');
#endif
}
@@ -98,45 +98,43 @@ void PIScreenDrawer::clear() {
void PIScreenDrawer::drawPixel(int x, int y, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x < 0 || x >= width || y < 0 || y >= height) return;
cells[y][x].symbol = c;
cells[y][x].symbol = c;
cells[y][x].format.color_char = col_char;
cells[y][x].format.color_back = col_back;
cells[y][x].format.flags = flags_char;
cells[y][x].format.flags = flags_char;
}
void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc;
cc.symbol = c;
cc.symbol = c;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
cc.format.flags = flags_char;
int x = 0, y = 0;
if (piAbsi(x1 - x0) >= piAbsi(y1 - y0)) {
float dy = (y1 - y0) / float(piAbsi(x1 - x0)), cy = y0;
int dx = x0 < x1 ? 1 : -1;
for (int i = x0; i != x1; i += dx) {
x = i; y = piRound(cy);
if (x >= 0 && x < width && y >= 0 && y < height)
cells[y][x] = cc;
x = i;
y = piRound(cy);
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc;
cy += dy;
}
y = piRound(cy);
if (x1 >= 0 && x1 < width && y >= 0 && y < height)
cells[y][x1] = cc;
if (x1 >= 0 && x1 < width && y >= 0 && y < height) cells[y][x1] = cc;
} else {
float dx = (x1 - x0) / float(piAbsi(y1 - y0)), cx = x0;
int dy = y0 < y1 ? 1 : -1;
for (int i = y0; i != y1; i += dy) {
x = piRound(cx); y = i;
if (x >= 0 && x < width && y >= 0 && y < height)
cells[y][x] = cc;
x = piRound(cx);
y = i;
if (x >= 0 && x < width && y >= 0 && y < height) cells[y][x] = cc;
cx += dx;
}
x = piRound(cx);
if (x >= 0 && x < width && y1 >= 0 && y1 < height)
cells[y1][x] = cc;
if (x >= 0 && x < width && y1 >= 0 && y1 < height) cells[y1][x] = cc;
}
}
@@ -144,32 +142,29 @@ void PIScreenDrawer::drawLine(int x0, int y0, int x1, int y1, const PIChar & c,
void PIScreenDrawer::drawRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc;
cc.symbol = c;
cc.symbol = c;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) {
int j = ys[k];
if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width)
cv[i] = cc;
if (i >= 0 && i < width) cv[i] = cc;
}
j = xs[k];
if (j >= 0 && j < width) {
for (int i = y0; i != y1; i += dy)
if (i >= 0 && i < height)
cells[i][j] = cc;
if (i >= 0 && i < height) cells[i][j] = cc;
}
}
int i = x1, j = y1;
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;
}
@@ -178,35 +173,37 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
Cell cc;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
int xs[2] = {x0, x1};
int ys[2] = {y0, y1};
for (int k = 0; k < 2; ++k) {
int j = ys[k];
if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]);
cc.symbol = artChar(LineHorizontal);
for (int i = x0 + 1; i != x1; i += dx)
if (i >= 0 && i < width)
cv[i] = cc;
if (i >= 0 && i < width) cv[i] = cc;
}
j = xs[k];
if (j >= 0 && j < width) {
cc.symbol = artChar(LineVertical);
for (int i = y0 + 1; i != y1; i += dy)
if (i >= 0 && i < height)
cells[i][j] = cc;
if (i >= 0 && i < height) 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;
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;
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;
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;
}
@@ -214,23 +211,22 @@ void PIScreenDrawer::drawFrame(int x0, int y0, int x1, int y1, Color col_char, C
void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, Color col_char, Color col_back, CharFlags flags_char) {
if (x0 == x1 && y0 == y1) drawPixel(x0, y0, c, col_char, col_back, flags_char);
Cell cc;
cc.symbol = c;
cc.symbol = c;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
cc.format.flags = flags_char;
int dx = x0 < x1 ? 1 : -1;
int dy = y0 < y1 ? 1 : -1;
for (int j = y0; j != y1; j += dy)
if (j >= 0 && j < height) {
PIVector<Cell> & cv(cells[j]);
for (int i = x0; i != x1; i += dx)
if (i >= 0 && i < width)
cv[i] = cc;
if (i >= 0 && i < width) cv[i] = cc;
}
}
void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<Cell> > & content) {
void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<Cell>> & content) {
if (x0 > x1) piSwap(x0, x1);
if (y0 > y1) piSwap(y0, y1);
int w = x1 - x0;
@@ -241,14 +237,13 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector<PIVector<
PIVector<Cell> & cv(cells[y0 + j]);
PIVector<Cell> & contv(content[j]);
for (int i = 0; i < piMini(w, contv.size_s()); ++i)
if ((i + x0) >= 0 && (i + x0) < width)
cv[x0 + i] = contv[i];
if ((i + x0) >= 0 && (i + x0) < width) cv[x0 + i] = contv[i];
}
}
}
void PIScreenDrawer::clear(PIVector<PIVector<Cell> > & cells) {
void PIScreenDrawer::clear(PIVector<PIVector<Cell>> & cells) {
for (int i = 0; i < cells.size_s(); ++i)
cells[i].fill(Cell());
}
@@ -260,12 +255,12 @@ void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char,
Cell cc;
cc.format.color_char = col_char;
cc.format.color_back = col_back;
cc.format.flags = flags_char;
cc.format.flags = flags_char;
for (int i = 0; i < s.size_s(); ++i) {
int j = i + x;
if (j >= 0 && j < width) {
cc.symbol = s[i];
cv[j] = cc;
cv[j] = cc;
}
}
}

View File

@@ -1,23 +1,24 @@
/*
PIP - Platform Independent Primitives
Basic PIScreen tile
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Basic PIScreen tile
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 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.
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/>.
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 "piscreentile.h"
#include "piscreendrawer.h"
@@ -25,24 +26,23 @@ using namespace PIScreenTypes;
PIScreenTile::PIScreenTile(const PIString & n, Direction d, SizePolicy p): PIObject(n) {
direction = d;
size_policy = p;
focus_flags = 0;
screen = 0;
direction = d;
size_policy = p;
focus_flags = 0;
screen = 0;
minimumWidth = minimumHeight = x_ = y_ = width_ = height_ = pw = ph = 0;
maximumWidth = maximumHeight = 65535;
marginLeft = marginRight = marginTop = marginBottom = spacing = 0;
parent = 0;
back_symbol = ' ';
visible = true;
has_focus = false;
parent = 0;
back_symbol = ' ';
visible = true;
has_focus = false;
}
PIScreenTile::~PIScreenTile() {
//piCout << this << "~";
if (screen)
screen->tileRemovedInternal(this);
// piCout << this << "~";
if (screen) screen->tileRemovedInternal(this);
setScreen(0);
deleteChildren();
if (!parent) return;
@@ -76,20 +76,18 @@ void PIScreenTile::removeTile(PIScreenTile * t) {
}
PIVector<PIScreenTile * > PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile * > ret;
piForeach (PIScreenTile * t, tiles)
if (t->visible || !only_visible)
ret << t << t->children(only_visible);
PIVector<PIScreenTile *> PIScreenTile::children(bool only_visible) {
PIVector<PIScreenTile *> ret;
piForeach(PIScreenTile * t, tiles)
if (t->visible || !only_visible) ret << t << t->children(only_visible);
return ret;
}
PIScreenTile * PIScreenTile::childUnderMouse(int x, int y) {
piForeach (PIScreenTile * t, tiles) {
piForeach(PIScreenTile * t, tiles) {
if (!t->visible) continue;
if (x >= t->x_ && (x - t->x_) < t->width_ &&
y >= t->y_ && (y - t->y_) < t->height_) {
if (x >= t->x_ && (x - t->x_) < t->width_ && y >= t->y_ && (y - t->y_) < t->height_) {
return t;
}
}
@@ -105,13 +103,13 @@ void PIScreenTile::raiseEvent(TileEvent e) {
void PIScreenTile::setScreen(PIScreenBase * s) {
screen = s;
piForeach (PIScreenTile * t, tiles)
piForeach(PIScreenTile * t, tiles)
t->setScreen(s);
}
void PIScreenTile::deleteChildren() {
piForeach (PIScreenTile * t, tiles) {
piForeach(PIScreenTile * t, tiles) {
t->parent = 0;
delete t;
}
@@ -129,9 +127,16 @@ void PIScreenTile::drawEventInternal(PIScreenDrawer * d) {
if (!visible) {
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);
piForeach (PIScreenTile * t, tiles)
piForeach(PIScreenTile * t, tiles)
t->drawEventInternal(d);
}
@@ -141,18 +146,22 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
h = 0;
if (tiles.isEmpty()) return;
int sl = spacing * (tiles.size_s() - 1);
if (direction == Horizontal) w += sl;
else h += sl;
piForeachC (PIScreenTile * t, tiles) {
if (direction == Horizontal)
w += sl;
else
h += sl;
piForeachC(PIScreenTile * t, tiles) {
if (!t->visible) continue;
int cw(0), ch(0);
t->sizeHint(cw, ch);
cw = piClampi(cw, t->minimumWidth, t->maximumWidth);
ch = piClampi(ch, t->minimumHeight, t->maximumHeight);
if (direction == Horizontal) {
w += cw; h = piMaxi(h, ch);
w += cw;
h = piMaxi(h, ch);
} else {
h += ch; w = piMaxi(w, cw);
h += ch;
w = piMaxi(w, cw);
}
}
w += marginLeft + marginRight;
@@ -163,7 +172,7 @@ void PIScreenTile::sizeHint(int & w, int & h) const {
void PIScreenTile::layout() {
if (tiles.isEmpty() || !visible) return;
int as(0), ts(0), ts2(0), ecnt(0), pcnt(0);
ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
ts = (direction == Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
ts2 = (direction != Horizontal) ? (width_ - marginLeft - marginRight) : (height_ - marginTop - marginBottom);
ts -= spacing * (tiles.size_s() - 1);
PIVector<int> hints(tiles.size_s());
@@ -180,7 +189,7 @@ void PIScreenTile::layout() {
cs = (direction == Horizontal) ? cw : ch;
as += cs;
}
hints[i] = cs;
hints[i] = cs;
asizes[i] = 0.f;
}
if (as <= ts) {
@@ -188,10 +197,10 @@ void PIScreenTile::layout() {
SizePolicy pol = Fixed;
if (ecnt > 0) {
acnt = ecnt;
pol = Expanding;
pol = Expanding;
} else if (pcnt > 0) {
acnt = pcnt;
pol = Preferred;
pol = Preferred;
}
if (acnt > 0) {
float add_a = float(ts - as), add_s = add_a / acnt, add_da(0.);
@@ -210,8 +219,7 @@ void PIScreenTile::layout() {
for (int j = 0; j < tiles.size_s(); ++j) {
if (i == j) continue;
if (max_tl[j]) continue;
if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout())
asizes[j] += pas;
if (tiles[j]->size_policy == pol && tiles[j]->visible && tiles[j]->needLayout()) asizes[j] += pas;
}
}
}
@@ -233,16 +241,15 @@ void PIScreenTile::layout() {
t->x_ = cx;
t->y_ = cy;
if (direction == Horizontal) {
t->width_ = hints[i];
t->width_ = hints[i];
t->height_ = ts2;
cx += hints[i] + spacing;
} else {
t->width_ = ts2;
t->width_ = ts2;
t->height_ = hints[i];
cy += hints[i] + spacing;
}
if (t->pw != t->width_ || t->ph != t->height_)
t->resizeEvent(t->width_, t->height_);
if (t->pw != t->width_ || t->ph != t->height_) t->resizeEvent(t->width_, t->height_);
t->pw = t->width_;
t->ph = t->height_;
t->layout();

View File

@@ -1,23 +1,24 @@
/*
PIP - Platform Independent Primitives
Various tiles for PIScreen
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Various tiles for PIScreen
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 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.
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/>.
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 "piscreentiles.h"
#include "piscreendrawer.h"
@@ -37,7 +38,7 @@ TileSimple::TileSimple(const TileSimple::Row & r): PIScreenTile() {
void TileSimple::sizeHint(int & w, int & h) const {
w = h = 0;
piForeachC (Row & r, content)
piForeachC(Row & r, content)
w = piMaxi(w, r.first.size_s());
h = content.size_s();
}
@@ -57,13 +58,13 @@ void TileSimple::drawEvent(PIScreenDrawer * d) {
}
// TileScrollBar
TileScrollBar::TileScrollBar(const PIString & n) {
direction = Vertical;
thickness = 1;
minimum_ = value_ = 0;
maximum_ = 100;
maximum_ = 100;
}
@@ -122,15 +123,15 @@ bool TileScrollBar::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileList
TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
alignment = Left;
alignment = Left;
focus_flags = CanHasFocus | NextByArrowsHorizontal | NextByTab | FocusOnMouseOrWheel;
lhei = offset = cur = 0;
mouse_sel = false;
selection_mode = sm;
scroll = new TileScrollBar();
mouse_sel = false;
selection_mode = sm;
scroll = new TileScrollBar();
scroll->size_policy = Ignore;
addTile(scroll);
}
@@ -138,26 +139,26 @@ TileList::TileList(const PIString & n, SelectionMode sm): PIScreenTile(n) {
void TileList::sizeHint(int & w, int & h) const {
w = h = 0;
piForeachC (Row & r, content)
piForeachC(Row & r, content)
w = piMaxi(w, r.first.size_s());
h = 3;
}
void TileList::resizeEvent(int w, int h) {
scroll->x_ = x_ + width_ - 1;
scroll->y_ = y_;
scroll->width_ = 1;
scroll->x_ = x_ + width_ - 1;
scroll->y_ = y_;
scroll->width_ = 1;
scroll->height_ = height_;
}
void TileList::drawEvent(PIScreenDrawer * d) {
lhei = height_ - 2;
lhei = height_ - 2;
int is = piClampi(offset, 0, piMaxi(0, content.size_s() - 1)), ie = piClampi(offset + lhei, 0, content.size_s());
if (is > 0) d->drawText(x_, y_, PIString(" /\\ ").repeat(width_ / 4), Green, Default, Bold);
if (ie < content.size_s()) d->drawText(x_, y_ + height_ - 1, PIString(" \\/ ").repeat(width_ / 4), Green, Default, Bold);
//piCout << is << ie << offset << lhei << content.size_s();
// piCout << is << ie << offset << lhei << content.size_s();
for (int i = is; i < ie; ++i) {
Row & r(content[i]);
bool sel = i == cur && has_focus;
@@ -172,7 +173,7 @@ void TileList::drawEvent(PIScreenDrawer * d) {
case Right: rx = x_ + width_ - 1 - r.first.size_s(); break;
};
CharFlags cf = r.second.flags;
Color cc = (Color)r.second.color_char;
Color cc = (Color)r.second.color_char;
if (selected[i]) {
cf |= Bold;
cc = Yellow;
@@ -188,9 +189,7 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
lhei = height_ - 2;
int oo(0), osp = piMini(3, lhei / 4);
switch (key.key) {
case PIKbdListener::PageUp:
cur -= lhei / 2;
oo -= lhei / 2;
case PIKbdListener::PageUp: cur -= lhei / 2; oo -= lhei / 2;
case PIKbdListener::UpArrow:
cur--;
oo--;
@@ -207,7 +206,8 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
switch (selection_mode) {
case NoSelection: return false;
case SingleSelection:
if (selected.isEmpty()) selected << cur;
if (selected.isEmpty())
selected << cur;
else {
bool add = !selected[cur];
selected.clear();
@@ -216,8 +216,10 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
raiseEvent(TileEvent(SelectionChanged));
return true;
case MultiSelection:
if (selected[cur]) selected.remove(cur);
else selected << cur;
if (selected[cur])
selected.remove(cur);
else
selected << cur;
raiseEvent(TileEvent(SelectionChanged));
break;
}
@@ -238,17 +240,14 @@ bool TileList::keyEvent(PIKbdListener::KeyEvent key) {
if (offset >= content.size_s() - lhei) offset = content.size_s() - lhei;
if (offset < 0) offset = 0;
return true;
case PIKbdListener::Home:
cur = offset = 0;
return true;
case PIKbdListener::Home: cur = offset = 0; return true;
case PIKbdListener::End:
cur = content.size_s() - 1;
cur = content.size_s() - 1;
offset = content.size_s() - lhei;
if (offset < 0) offset = 0;
return true;
case PIKbdListener::Return:
if (cur >= 0 && cur < content.size_s())
raiseEvent(TileEvent(RowPressed, cur));
if (cur >= 0 && cur < content.size_s()) raiseEvent(TileEvent(RowPressed, cur));
return true;
case '*':
if (selection_mode == TileList::MultiSelection) {
@@ -278,12 +277,8 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
if (mp < 0 || mp >= content.size_s()) return true;
cur = mp;
switch (me.action) {
case PIKbdListener::MouseButtonPress:
mouse_sel = !selected.contains(cur);
break;
case PIKbdListener::MouseButtonDblClick:
keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return));
return true;
case PIKbdListener::MouseButtonPress: mouse_sel = !selected.contains(cur); break;
case PIKbdListener::MouseButtonDblClick: keyEvent(PIKbdListener::KeyEvent(PIKbdListener::Return)); return true;
default: break;
}
if (me.buttons[PIKbdListener::MouseRight]) {
@@ -294,8 +289,10 @@ bool TileList::mouseEvent(PIKbdListener::MouseEvent me) {
raiseEvent(TileEvent(SelectionChanged));
break;
case MultiSelection:
if (mouse_sel) selected << cur;
else selected.remove(cur);
if (mouse_sel)
selected << cur;
else
selected.remove(cur);
raiseEvent(TileEvent(SelectionChanged));
break;
default: break;
@@ -311,7 +308,7 @@ bool TileList::wheelEvent(PIKbdListener::WheelEvent we) {
}
// TileButton
TileButton::TileButton(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
@@ -327,7 +324,7 @@ void TileButton::sizeHint(int & w, int & h) const {
void TileButton::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan;
Color ct = has_focus ? White : Black;
int ff = has_focus ? Bold : 0;
int ff = has_focus ? Bold : 0;
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
d->drawText(x_, y_, "[", ct, Transparent, ff);
d->drawText(x_ + (width_ - text.size_s()) / 2, y_, text, ct, Transparent, ff);
@@ -351,25 +348,25 @@ bool TileButton::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileButtons
TileButtons::TileButtons(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
direction = Horizontal;
alignment = PIScreenTypes::Center;
cur = 0;
direction = Horizontal;
alignment = PIScreenTypes::Center;
cur = 0;
}
void TileButtons::sizeHint(int & w, int & h) const {
w = h = 0;
if (direction == Horizontal) {
piForeachC (Button & b, content)
piForeachC(Button & b, content)
w += b.first.size_s() + 4;
w += piMaxi(0, content.size_s() - 1) * 2;
h += 1;
} else {
piForeachC (Button & b, content)
piForeachC(Button & b, content)
w = piMaxi(w, b.first.size_s() + 4);
h += content.size_s();
h += piMaxi(0, content.size_s() - 1);
@@ -387,12 +384,11 @@ void TileButtons::drawEvent(PIScreenDrawer * d) {
case PIScreenTypes::Right: dx = width_ - shw; break;
default: break;
}
if (direction == PIScreenTypes::Horizontal)
cx += dx;
if (direction == PIScreenTypes::Horizontal) cx += dx;
for (int i = 0; i < content.size_s(); ++i) {
Color cb = Cyan;
Color ct = Black;
int ff = 0;
int ff = 0;
if (i == cur && has_focus) {
cb = Blue;
ct = White;
@@ -430,9 +426,7 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
if (cur >= content.size_s()) cur = content.size_s() - 1;
return true;
case PIKbdListener::Space:
case PIKbdListener::Return:
raiseEvent(TileEvent(ButtonSelected, cur));
return true;
case PIKbdListener::Return: raiseEvent(TileEvent(ButtonSelected, cur)); return true;
};
return PIScreenTile::keyEvent(key);
}
@@ -441,8 +435,7 @@ bool TileButtons::keyEvent(PIKbdListener::KeyEvent key) {
bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
if (me.action == PIKbdListener::MouseMove || me.action == PIKbdListener::MouseButtonPress) {
for (int i = 0; i < btn_rects.size_s(); ++i)
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) {
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) {
cur = i;
break;
}
@@ -454,11 +447,11 @@ bool TileButtons::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileCheck
TileCheck::TileCheck(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | NextByArrowsAll | FocusOnMouse;
toggled = false;
toggled = false;
}
@@ -471,7 +464,7 @@ void TileCheck::sizeHint(int & w, int & h) const {
void TileCheck::drawEvent(PIScreenDrawer * d) {
Color cb = has_focus ? Blue : Cyan;
Color ct = has_focus ? White : Black;
int ff = has_focus ? Bold : 0;
int ff = has_focus ? Bold : 0;
PIString cs("[ ]");
if (toggled) cs[1] = '*';
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, cb);
@@ -499,12 +492,12 @@ bool TileCheck::mouseEvent(PIKbdListener::MouseEvent me) {
}
// TileProgress
TileProgress::TileProgress(const PIString & n): PIScreenTile(n) {
maximum = 100.;
value = 0.;
suffix = " %";
value = 0.;
suffix = " %";
}
@@ -515,7 +508,7 @@ void TileProgress::sizeHint(int & w, int & h) const {
void TileProgress::drawEvent(PIScreenDrawer * d) {
int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100);
int v = maximum == 0. ? 0 : piClampd(piRoundd(value / maximum * 100.), 0, 100);
PIString s = prefix + PIString::fromNumber(piRoundd(value)) + suffix;
int w = piRoundd(v / 100. * width_), sx = (width_ - s.size_s()) / 2;
d->fillRect(x_, y_, x_ + width_, y_ + 1, ' ', Default, Cyan);
@@ -532,28 +525,26 @@ void TileProgress::drawEvent(PIScreenDrawer * d) {
}
// TilePICout
TilePICout::TilePICout(const PIString & n): TileList(n) {
max_lines = 1024;
max_lines = 1024;
selection_mode = TileList::SingleSelection;
PICout::setOutputDevices(PICout::Buffer);
PICout::setBufferActive(true);
}
void TilePICout::drawEvent(PIScreenDrawer * d) {
PIString out = PICout::buffer(true);
PIString out = PICout::getBufferAndClear();
if (!out.isEmpty()) {
PIStringList l = out.split("\n");
bool scroll = (cur == content.size_s() - 1) || !has_focus;
piForeachC (PIString & s, l)
bool scroll = (cur == content.size_s() - 1) || !has_focus;
piForeachC(PIString & s, l)
content << TileList::Row(s.trimmed(), format);
if (content.size_s() > max_lines)
content.remove(0, content.size_s() - max_lines);
if (content.size_s() > max_lines) content.remove(0, content.size_s() - max_lines);
if (scroll) {
offset = piMaxi(0, content.size_s() - lhei);
cur = content.size_s() - 1;
cur = content.size_s() - 1;
}
}
TileList::drawEvent(d);
@@ -570,16 +561,16 @@ bool TilePICout::keyEvent(PIKbdListener::KeyEvent key) {
}
// TileInput
TileInput::TileInput(const PIString & n): PIScreenTile(n) {
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
focus_flags = CanHasFocus | NextByTab | FocusOnMouse;
back_format.color_back = White;
format.color_char = Black;
format.color_back = White;
max_length = 1024;
format.color_char = Black;
format.color_back = White;
max_length = 1024;
cur = offset = 0;
inv = false;
inv = false;
}
@@ -592,10 +583,8 @@ void TileInput::sizeHint(int & w, int & h) const {
void TileInput::drawEvent(PIScreenDrawer * d) {
PIString ps = text.mid(offset, width_ - 2);
d->drawText(x_ + 1, y_, ps, (Color)format.color_char, Transparent, (CharFlags)format.flags);
if (offset > 0)
d->drawText(x_, y_, "<", Green, Black, Bold);
if (text.size_s() - offset >= width_ - 2)
d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold);
if (offset > 0) d->drawText(x_, y_, "<", Green, Black, Bold);
if (text.size_s() - offset >= width_ - 2) d->drawText(x_ + width_ - 1, y_, ">", Green, Black, Bold);
if (!has_focus) return;
Color cb = (Color)format.color_char, cc = (Color)format.color_back;
if (tm_blink.elapsed_m() >= 650) {
@@ -642,14 +631,13 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor();
return true;
case PIKbdListener::End:
cur = text.size_s();
cur = text.size_s();
offset = text.size_s() - lwid;
if (offset < 0) offset = 0;
reserCursor();
return true;
case PIKbdListener::Backspace:
if (cur > text.size_s() || text.isEmpty())
return true;
if (cur > text.size_s() || text.isEmpty()) return true;
text.remove(cur - 1, 1);
cur--;
if (cur > text.size_s()) cur = text.size_s();
@@ -659,8 +647,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
reserCursor();
return true;
case PIKbdListener::Delete:
if (cur >= text.size_s() || text.isEmpty())
return true;
if (cur >= text.size_s() || text.isEmpty()) return true;
text.remove(cur, 1);
if (cur < 0) cur = 0;
if (cur > text.size_s()) cur = text.size_s();
@@ -686,16 +673,9 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
case PIKbdListener::F9:
case PIKbdListener::F10:
case PIKbdListener::F11:
case PIKbdListener::F12:
break;
case PIKbdListener::F12: break;
default:
PIChar tc
#ifdef WINDOWS
= PIChar(key.key);
#else
= PIChar::fromUTF8((char *)&(key.key));
#endif
text.insert(cur, tc);
text.insert(cur, PIChar((ushort)key.key));
cur++;
oo++;
if (cur - offset >= lwid - osp) offset += oo;

View File

@@ -1,57 +1,60 @@
/*
PIP - Platform Independent Primitives
Virtual terminal
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Virtual terminal
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 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.
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/>.
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 "piincludes_p.h"
#include "piterminal.h"
#include "piincludes_p.h"
#include "pisharedmemory.h"
#ifndef FREERTOS
#ifdef WINDOWS
# include <windows.h>
# include <wincon.h>
# include <winuser.h>
#else
# include "piprocess.h"
# include <csignal>
# include <fcntl.h>
# include <sys/ioctl.h>
# if defined(QNX) || defined(BLACKBERRY)
# include <unix.h>
#ifndef MICRO_PIP
# ifdef WINDOWS
# include <wincon.h>
# include <windows.h>
# include <wingdi.h>
# include <winuser.h>
# else
# ifdef MAC_OS
# include <util.h>
# else
# include <pty.h>
# endif
# include "piprocess.h"
# include <csignal>
# include <fcntl.h>
# include <sys/ioctl.h>
# if defined(QNX) || defined(BLACKBERRY)
# include <unix.h>
# else
# ifdef MAC_OS
# include <util.h>
# else
# include <pty.h>
# endif
# endif
# ifdef ANDROID
# if __ANDROID_API__ >= 23
# define HAS_FORKPTY
# endif
# else
# define HAS_FORKPTY
# endif
# endif
# ifdef ANDROID
# if __ANDROID_API__ >= 23
# define HAS_FORKPTY
# endif
# else
# define HAS_FORKPTY
# endif
#endif
//extern PIMutex PICout::__mutex__;
// extern PIMutex PICout::__mutex__;
#ifdef WINDOWS
# define PIPE_BUFFER_SIZE 1024
# ifdef WINDOWS
# define PIPE_BUFFER_SIZE 1024
enum PITerminalAuxMessageType {
mtKey = 1,
mtResize,
@@ -64,22 +67,22 @@ struct PITerminalAuxData {
int size_y;
int cells_size;
};
#else
# define BUFFER_SIZE 4096
# else
# define BUFFER_SIZE 4096
enum DECType {
CKM = 1
};
#endif
# endif
PRIVATE_DEFINITION_START(PITerminal)
#ifdef WINDOWS
# ifdef WINDOWS
PISharedMemory * shm;
HANDLE hConBuf;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
HANDLE pipe;
#else
# else
PIString shell;
PIByteArray read_buf, tmp_buf;
PIScreenTypes::CellFormat cur_format, line_format;
@@ -91,21 +94,21 @@ PRIVATE_DEFINITION_START(PITerminal)
PIString esc_seq;
bool is_esc_seq, last_read;
PIMap<int, bool> DEC;
PIVector<PIVector<PIScreenTypes::Cell> > cells_save;
#endif
PIVector<PIVector<PIScreenTypes::Cell>> cells_save;
# endif
PRIVATE_DEFINITION_END(PITerminal)
#ifdef WINDOWS
# ifdef WINDOWS
int writePipe(HANDLE pipe, const PIByteArray & ba) {
DWORD wrote[2];
int sz = ba.size_s();
WriteFile(pipe, &sz, 4, &(wrote[0]), 0);
WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0);
//piCout << "send" << ba.size_s();
// piCout << "send" << ba.size_s();
return int(wrote[0] + wrote[1]);
}
#endif
# endif
PITerminal::PITerminal(): PIThread() {
@@ -113,42 +116,41 @@ PITerminal::PITerminal(): PIThread() {
initPrivate();
cursor_blink = false;
cursor_x = cursor_y = 0;
dsize_x = 80;
dsize_y = 24;
#ifdef WINDOWS
dsize_x = 80;
dsize_y = 24;
# ifdef WINDOWS
PRIVATE->shm = 0;
#endif
# endif
}
PITerminal::~PITerminal() {
if (isRunning())
stop();
if (isRunning()) stop();
PIThread::waitForFinish(10);
destroy();
#ifdef WINDOWS
# ifdef WINDOWS
if (PRIVATE->shm) delete PRIVATE->shm;
#endif
# endif
}
void PITerminal::write(const PIByteArray & d) {
#ifdef WINDOWS
# ifdef WINDOWS
PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke;
for (int i = 0; i < d.size_s(); ++i)
ke << PIKbdListener::KeyEvent(d[i]);
msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg);
#else
# ifdef HAS_FORKPTY
# else
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return;
//ssize_t wrote = 0;
//wrote =
// ssize_t wrote = 0;
// wrote =
::write(PRIVATE->fd, d.data(), d.size_s());
//piCout << "wrote" << wrote << d;
// piCout << "wrote" << wrote << d;
# endif
# endif
#endif
cursor_tm.reset();
cursor_blink = true;
}
@@ -156,15 +158,16 @@ void PITerminal::write(const PIByteArray & d) {
void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) {
PIByteArray ba;
#ifdef WINDOWS
# ifdef WINDOWS
switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break;
case PIKbdListener::Space: ba << uchar(' '); break;
case PIKbdListener::Space: ba << uchar(' '); break;
default: break;
}
//piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba);
// piCout << "write" << ba.size();
if (!ba.isEmpty())
write(ba);
else {
PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke;
@@ -172,19 +175,20 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg);
}
#else
int term = PRIVATE->term_type;
# else
int term = PRIVATE->term_type;
int flags = 0;
switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\n'); break;
case PIKbdListener::Esc: ba << uchar('\e'); break;
case PIKbdListener::Space: ba << uchar(' '); break;
case PIKbdListener::Backspace: ba << uchar(0x7f); break;
case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1;
case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\n'); break;
case PIKbdListener::Esc: ba << uchar('\e'); break;
case PIKbdListener::Space: ba << uchar(' '); break;
case PIKbdListener::Backspace: ba << uchar(0x7f); break;
case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow:
if (PRIVATE->DEC.value(CKM, false)) flags = 1;
/*case PIKbdListener::Home: //break;
case PIKbdListener::End: //break;
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
@@ -205,55 +209,55 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::F12: //break;
*/
default: {
//piCout << flags;
//int mod = 0;
// piCout << flags;
// int mod = 0;
if (m[PIKbdListener::Shift]) m |= 1;
if (m[PIKbdListener::Alt]) m |= 2;
if (m[PIKbdListener::Ctrl]) m |= 4;
for (int i = 0; ; ++i) {
if (m[PIKbdListener::Alt]) m |= 2;
if (m[PIKbdListener::Ctrl]) m |= 4;
for (int i = 0;; ++i) {
const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]);
if (!e.seq) break;
//piCout << "search" << rc[1] << esc_seq[i].seq;
// piCout << "search" << rc[1] << esc_seq[i].seq;
if (e.key == k && e.mod == m) {
if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) {
//piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e");
// piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e");
PIByteArray d = ("\e" + PIString(e.seq)).toByteArray();
write(d);
break;
}
}
}
} break;
} break;
}
//piCout << "write" << ba.size();
// piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba);
#endif
# endif
cursor_tm.reset();
cursor_blink = true;
}
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 {
PIByteArray ba;
#ifdef WINDOWS
ba << uchar(PIChar(ke.key).toConsole1Byte());
#else
ba = PIString(PIChar(ke.key)).toUTF8();
#endif
# ifdef WINDOWS
ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
# else
ba = PIString(PIChar((ushort)ke.key)).toUTF8();
# endif
write(ba);
}
}
PIVector<PIVector<PIScreenTypes::Cell> > PITerminal::content() {
PIVector<PIVector<PIScreenTypes::Cell>> PITerminal::content() {
readConsole();
PIVector<PIVector<PIScreenTypes::Cell> > ret = cells;
PIVector<PIVector<PIScreenTypes::Cell>> ret = cells;
if (cursor_blink && cursor_visible)
if (cursor_x >= 0 && cursor_x < size_x)
if (cursor_y >= 0 && cursor_y < size_y)
ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
if (cursor_y >= 0 && cursor_y < size_y) ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
return ret;
}
@@ -294,56 +298,56 @@ bool PITerminal::isSpecialKey(int k) {
void PITerminal::initPrivate() {
#ifdef WINDOWS
PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
PRIVATE->pipe = INVALID_HANDLE_VALUE;
# ifdef WINDOWS
PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
PRIVATE->pipe = INVALID_HANDLE_VALUE;
PRIVATE->pi.hProcess = 0;
#else
# else
PRIVATE->shell = "/bin/bash";
PRIVATE->read_buf.reserve(BUFFER_SIZE);
PRIVATE->read_buf.fill(0);
PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0;
PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0;
PRIVATE->pid = 0;
PRIVATE->term_type = 0;
PRIVATE->is_esc_seq = false;
PRIVATE->last_read = true;
PRIVATE->pid = 0;
PRIVATE->term_type = 0;
PRIVATE->is_esc_seq = false;
PRIVATE->last_read = true;
PRIVATE->esc_seq.clear();
PRIVATE->cur_format = PIScreenTypes::CellFormat();
#endif
# endif
cursor_blink = cursor_visible = true;
size_x = size_y = 0;
}
void PITerminal::readConsole() {
#ifdef WINDOWS
# ifdef WINDOWS
if (!PRIVATE->shm) return;
PITerminalAuxData data;
PRIVATE->shm->read(&data, sizeof(data));
if (data.cells_size <= 4) return;
cursor_x = data.cursor_x;
cursor_y = data.cursor_y;
size_x = data.size_x;
size_y = data.size_y;
size_x = data.size_x;
size_y = data.size_y;
PIByteArray ba;
ba.resize(data.cells_size);
PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data));
ba >> cells;
#endif
//piCout << cursor_x << cursor_y;
# endif
// piCout << cursor_x << cursor_y;
}
void PITerminal::getCursor(int & x, int & y) {
#ifdef WINDOWS
# ifdef WINDOWS
if (!PRIVATE->shm) return;
int sz = 0;
PRIVATE->shm->read(&sz, 4);
#else
x = PRIVATE->cur_x;
y = PRIVATE->cur_y;
#endif
# else
x = PRIVATE->cur_x;
y = PRIVATE->cur_y;
# endif
}
@@ -369,16 +373,16 @@ void PITerminal::run() {
cursor_tm.reset();
cursor_blink = !cursor_blink;
}
#ifndef WINDOWS
# ifdef HAS_FORKPTY
# ifndef WINDOWS
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return;
PRIVATE->tmp_buf.resize(BUFFER_SIZE);
int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s());
bool used = false;
bool used = false;
if (readed > 0) {
PRIVATE->last_read = true;
//piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
//piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
// piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
// piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed));
for (;;) {
int ind = -1;
@@ -394,28 +398,27 @@ void PITerminal::run() {
}
bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE;
if (PRIVATE->read_buf.size_s() == 1)
if (PRIVATE->read_buf[0] < 0x80)
parse = true;
if (PRIVATE->read_buf[0] < 0x80) parse = true;
if (parse) {
parseInput(PIString(PRIVATE->read_buf));
parseInput(PIString::fromUTF8(PRIVATE->read_buf));
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()) {
parseInput(PIString(PRIVATE->read_buf));
parseInput(PIString::fromUTF8(PRIVATE->read_buf));
PRIVATE->read_buf.clear();
}
PRIVATE->last_read = false;
# endif
# endif
#endif
}
#ifndef WINDOWS
# ifndef WINDOWS
void PITerminal::parseInput(const PIString & s) {
//piCoutObj << s.replaceAll("\e", "\\e");
//printf("%s", s.data());
// piCoutObj << s.replaceAll("\e", "\\e");
// printf("%s", s.data());
for (int i = 0; i < s.size_s(); ++i) {
if (s[i].unicode16Code() == 0) break;
if (PRIVATE->is_esc_seq) {
@@ -428,7 +431,7 @@ void PITerminal::parseInput(const PIString & s) {
if (isCompleteEscSeq(PRIVATE->esc_seq)) {
PRIVATE->is_esc_seq = false;
applyEscSeq(PRIVATE->esc_seq);
//piCoutObj << PRIVATE->esc_seq;
// piCoutObj << PRIVATE->esc_seq;
}
}
} else {
@@ -443,14 +446,15 @@ void PITerminal::parseInput(const PIString & s) {
}
if (s[i] == '\r') continue;
if (s[i] == '\n') {
//piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
// piCoutObj << "new line";
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->cur_x = 0;
PRIVATE->cur_x = 0;
moveCursor(0, 1);
continue;
}
//piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y;
// piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y;
cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i];
cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format;
moveCursor(1, 0);
@@ -474,10 +478,10 @@ bool PITerminal::isCompleteEscSeq(const PIString & es) {
void PITerminal::applyEscSeq(PIString es) {
piCoutObj << es;
if (es.size_s() < 2) return;
// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format);
// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format);
PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format);
if (es[1] == '?' && es.size_s() >= 2) {
char a = es.takeRight(1)[0].toAscii();
char a = es.takeRight(1)[0].toAscii();
bool val = false;
if (a == 'l') val = false;
if (a == 'h') val = true;
@@ -497,7 +501,8 @@ void PITerminal::applyEscSeq(PIString es) {
case 1047:
if (val) {
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 {
cells = PRIVATE->cells_save;
}
@@ -512,7 +517,7 @@ void PITerminal::applyEscSeq(PIString es) {
return;
}
PIStringList args = es.split(";");
piForeachC (PIString & a, args) {
piForeachC(PIString & a, args) {
int av = a.toInt();
switch (av) {
case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break;
@@ -523,8 +528,14 @@ void PITerminal::applyEscSeq(PIString es) {
default: {
bool col = false, target = false;
int cid = av % 10;
if (av >= 30 && av <= 37) {col = true; target = false;}
if (av >= 40 && av <= 47) {col = true; target = true;}
if (av >= 30 && av <= 37) {
col = true;
target = false;
}
if (av >= 40 && av <= 47) {
col = true;
target = true;
}
if (col) {
int cfl = 0;
switch (cid) {
@@ -543,13 +554,13 @@ void PITerminal::applyEscSeq(PIString es) {
PRIVATE->cur_format.color_char = cfl;
break;
}
} break;
} break;
}
}
/*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) {
uchar t = PRIVATE->cur_format.color_char;
PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back;
PRIVATE->cur_format.color_back = t;
uchar t = PRIVATE->cur_format.color_char;
PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back;
PRIVATE->cur_format.color_back = t;
}*/
}
if (es.back() == 'r') {
@@ -578,33 +589,37 @@ void PITerminal::applyEscSeq(PIString es) {
int x(0), y(0);
if (!args[0].isEmpty()) y = args[0].toInt() - 1;
if (!args[1].isEmpty()) x = args[1].toInt() - 1;
//piCoutObj << x << y;
PRIVATE->cur_x = piClamp(x, 0, size_x - 1);
PRIVATE->cur_y = piClamp(y, 0, size_y - 1);
// piCoutObj << x << y;
PRIVATE->cur_x = piClamp(x, 0, size_x - 1);
PRIVATE->cur_y = piClamp(y, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'A') { // cursor up
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'B') { // cursor down
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'D') { // cursor back
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'G' || es.back() == '`') { // goto column
@@ -615,66 +630,92 @@ void PITerminal::applyEscSeq(PIString es) {
}
if (es.back() == 'd') { // goto line
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'E' || es.back() == 'e') { // next line
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'F') { // previous line
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
int v = es.toInt();
if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'L') { // insert lines
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
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];
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;
int v = es.toInt();
if (v == 0) v = 1;
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];
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
es.cutLeft(1).cutRight(1);
int v = es.toInt(); 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];
int v = es.toInt();
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 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
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
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;
int v = es.toInt();
if (v == 0) v = 1;
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
es.cutLeft(1).cutRight(1);
int v = es.toInt(); if (v == 0) v = 1;
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;
int v = es.toInt();
if (v == 0) v = 1;
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
es.cutLeft(1).cutRight(1);
int v = es.toInt();
switch (v) {
case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell);
for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i)
cells[i].fill(def_cell);
break;
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_y; ++i) cells[i].fill(def_cell);
for (int i = 0; i <= PRIVATE->cur_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = 0; i < PRIVATE->cur_y; ++i)
cells[i].fill(def_cell);
break;
case 2:
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
//PRIVATE->cur_x = PRIVATE->cur_y = 0;
for (int i = 0; i < size_y; ++i)
cells[i].fill(def_cell);
// PRIVATE->cur_x = PRIVATE->cur_y = 0;
break;
}
}
@@ -683,14 +724,14 @@ void PITerminal::applyEscSeq(PIString es) {
int v = es.toInt();
switch (v) {
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;
case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
break;
case 2:
cells[PRIVATE->cur_y].fill(def_cell);
for (int i = 0; i <= PRIVATE->cur_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
break;
case 2: cells[PRIVATE->cur_y].fill(def_cell); break;
}
}
}
@@ -704,12 +745,12 @@ void PITerminal::moveCursor(int dx, int dy) {
if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0;
if (PRIVATE->cur_x >= size_x) {
PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0;
PRIVATE->cur_x = 0;
PRIVATE->cur_y++;
}
if (PRIVATE->cur_y >= size_y) {
int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1);
//piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1);
// piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
PRIVATE->cur_y = size_y - 1;
for (int y = 0; y < size_y - scroll; ++y)
cells[y] = cells[y + scroll];
@@ -720,58 +761,76 @@ void PITerminal::moveCursor(int dx, int dy) {
int PITerminal::termType(const PIString & t) {
if (t == "xterm") return PIKbdListener::vt_xterm;
else if (t == "linux") return PIKbdListener::vt_linux;
if (t == "xterm")
return PIKbdListener::vt_xterm;
else if (t == "linux")
return PIKbdListener::vt_linux;
return PIKbdListener::vt_none;
}
#endif
# endif
bool PITerminal::initialize() {
destroy();
#ifdef WINDOWS
# ifdef WINDOWS
/*SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true;
sa.lpSecurityDescriptor = 0;
if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) {
piCoutObj << "CreatePipe error," << errorString();
initPrivate();
return false;
piCoutObj << "CreatePipe error," << errorString();
initPrivate();
return false;
}
PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0);
if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateConsoleScreenBuffer error," << errorString();
destroy();
return false;
piCoutObj << "CreateConsoleScreenBuffer error," << errorString();
destroy();
return false;
}*/
//CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
//SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
//SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
//GetStartupInfoA(&PRIVATE->si);
// CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
// SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
// SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
// GetStartupInfoA(&PRIVATE->si);
memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
PRIVATE->si.cb = sizeof(STARTUPINFO);
//PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
// PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS;
//PRIVATE->si.hStdInput = PRIVATE->pipe;
//PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
//PRIVATE->si.hStdError = PRIVATE->hConBuf;
PRIVATE->si.wShowWindow = SW_HIDE;
// PRIVATE->si.hStdInput = PRIVATE->pipe;
// PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
// PRIVATE->si.hStdError = PRIVATE->hConBuf;
PRIVATE->si.wShowWindow = SW_HIDE;
PRIVATE->si.dwXCountChars = 80;
PRIVATE->si.dwYCountChars = 24;
memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi));
PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString pname = "\\\\.\\pipe\\piterm" + shmh;
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)) {
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)) {
piCoutObj << "CreateProcess error," << errorString();
destroy();
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) {
piCoutObj << "CreateNamedPipe error," << errorString();
destroy();
@@ -791,31 +850,33 @@ bool PITerminal::initialize() {
return false;
}
if (PRIVATE->shm) delete PRIVATE->shm;
PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024*1024);
PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024 * 1024);
CloseHandle(PRIVATE->pi.hThread);
resize(dsize_x, dsize_y);
#else
# ifdef HAS_FORKPTY
char pty[256]; memset(pty, 0, 256);
# else
# ifdef HAS_FORKPTY
char pty[256];
memset(pty, 0, 256);
winsize ws;
ws.ws_col = dsize_x;
ws.ws_row = dsize_y;
ws.ws_col = dsize_x;
ws.ws_row = dsize_y;
PIStringList env = PIProcess::currentEnvironment();
piForeachC (PIString & e, env)
piForeachC(PIString & e, env)
if (e.startsWith("TERM=")) {
PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase());
//piCout << PRIVATE->term_type;
// piCout << PRIVATE->term_type;
break;
}
pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws);
//piCoutObj << fr << PRIVATE->fd << pty;
// piCoutObj << fr << PRIVATE->fd << pty;
if (fr == 0) {
char ** argv = new char*[2];
argv[0] = new char[PRIVATE->shell.lengthAscii() + 1];
memcpy(argv[0], PRIVATE->shell.dataAscii(), PRIVATE->shell.lengthAscii());
argv[0][PRIVATE->shell.lengthAscii()] = 0;
argv[1] = 0;
execvp(PRIVATE->shell.dataAscii(), argv);
char ** argv = new char *[2];
PIByteArray shell = PRIVATE->shell.toByteArray();
argv[0] = new char[shell.size() + 1];
memcpy(argv[0], shell.data(), shell.size());
argv[0][shell.size()] = 0;
argv[1] = 0;
execvp(argv[0], argv);
delete[] argv[0];
delete[] argv;
exit(0);
@@ -827,31 +888,31 @@ bool PITerminal::initialize() {
}
PRIVATE->pid = fr;
fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK);
/*
tcgetattr(PRIVATE->fd, &PRIVATE->desc);
PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0;
PRIVATE->desc.c_iflag = IGNBRK;
PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
PRIVATE->desc.c_cflag |= (CSIZE & CS8);
PRIVATE->desc.c_cflag |= CREAD;
PRIVATE->desc.c_cc[VMIN] = 1;
PRIVATE->desc.c_cc[VTIME] = 1;
/*
tcgetattr(PRIVATE->fd, &PRIVATE->desc);
PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0;
PRIVATE->desc.c_iflag = IGNBRK;
PRIVATE->desc.c_cflag = CLOCAL | HUPCL;
PRIVATE->desc.c_cflag |= (CSIZE & CS8);
PRIVATE->desc.c_cflag |= CREAD;
PRIVATE->desc.c_cc[VMIN] = 1;
PRIVATE->desc.c_cc[VTIME] = 1;
cfsetispeed(&PRIVATE->desc, B38400);
cfsetospeed(&PRIVATE->desc, B38400);
cfsetispeed(&PRIVATE->desc, B38400);
cfsetospeed(&PRIVATE->desc, B38400);
if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) {
piCoutObj << "Can`t set attributes for \"" << pty << "\"";
destroy();
return false;
}
*/
if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) {
piCoutObj << "Can`t set attributes for \"" << pty << "\"";
destroy();
return false;
}
*/
size_x = dsize_x;
size_y = dsize_y;
resize(size_x, size_y);
}
# endif
# endif
#endif
cursor_blink = false;
cursor_tm.reset();
start(40);
@@ -860,46 +921,44 @@ bool PITerminal::initialize() {
void PITerminal::destroy() {
//piCout << "destroy ...";
// piCout << "destroy ...";
stop();
waitForFinish(1000);
#ifdef WINDOWS
# ifdef WINDOWS
if (PRIVATE->pi.hProcess) {
//piCout << "term";
//TerminateProcess(PRIVATE->pi.hProcess, 0);
// piCout << "term";
// TerminateProcess(PRIVATE->pi.hProcess, 0);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId);
CloseHandle(PRIVATE->pi.hProcess);
}
if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe);
if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf);
//piCout << "destroy" << size_y;
#else
# ifdef HAS_FORKPTY
if (PRIVATE->pid != 0)
kill(PRIVATE->pid, SIGKILL);
if (PRIVATE->fd != 0)
::close(PRIVATE->fd);
// piCout << "destroy" << size_y;
# else
# ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL);
if (PRIVATE->fd != 0) ::close(PRIVATE->fd);
# endif
# endif
#endif
initPrivate();
}
bool PITerminal::resize(int cols, int rows) {
bool ret = true;
dsize_x = cols;
dsize_y = rows;
#ifdef WINDOWS
dsize_x = cols;
dsize_y = rows;
# ifdef WINDOWS
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false;
PIByteArray msg;
msg << int(mtResize) << dsize_x << dsize_y;
writePipe(PRIVATE->pipe, msg);
#else
# ifdef HAS_FORKPTY
# else
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return false;
size_x = dsize_x;
size_y = dsize_y;
//piCout << "resize" << PRIVATE->fd << size_x << size_y;
// piCout << "resize" << PRIVATE->fd << size_x << size_y;
winsize ws;
ws.ws_col = cols;
ws.ws_row = rows;
@@ -909,12 +968,12 @@ bool PITerminal::resize(int cols, int rows) {
PRIVATE->cells_save.resize(size_y);
for (int i = 0; i < size_y; ++i)
PRIVATE->cells_save[i].resize(size_x);
# endif
# endif
#endif
cells.resize(size_y);
for (int i = 0; i < size_y; ++i)
cells[i].resize(size_x);
return ret;
}
#endif // FREERTOS
#endif // MICRO_PIP

View File

@@ -1,297 +1,297 @@
/*
PIP - Platform Independent Primitives
PIP Authentication API
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 "piauth.h"
#define PIAUTH_NOISE_MAX_SIZE 256
PIAuth::PIAuth(const PIByteArray & sign) : PIObject() {
setName("Client");
role = Client;
state = NotConnected;
sign_sk = sign;
sign_pk = crypt.extractSignPublicKey(sign);
}
void PIAuth::setServerPassword(const PIString & ps) {
pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
}
void PIAuth::stop() {
role = Client;
state = NotConnected;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
}
void PIAuth::startClient() {
role = Client;
state = AuthProbe;
}
PIByteArray PIAuth::startServer() {
setName("Server");
role = Server;
state = AuthProbe;
PIByteArray ba;
crypt.generateKeypair(my_pk, box_sk);
PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE+128);
ba << (int)state << custom_info << sign_pk << my_pk << noise;
PIByteArray sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return ba;
}
PIAuth::State PIAuth::receive(PIByteArray & ba) {
if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size");
State rstate;
int s;
ba >> s;
rstate = (State)s;
// if (state != rstate) return disconect(ba);
//client side
if (role == Client) {
if (state == AuthProbe && rstate == AuthProbe) {
if (ba.size() < sizeof(int)*5) return disconnect(ba, "invalid data size");
PIByteArray rinfo;
PIByteArray rsign;
PIByteArray rsign_pk;
PIByteArray noise;
ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign;
if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size");
PIByteArray tba;
tba << (int)rstate << rinfo << rsign_pk << box_pk << noise;
if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign");
bool auth = false;
if (isAuthorizedKey(rsign_pk)) {
auth = true;
} else {
authorize(rinfo, &auth);
if (auth) auth_pkeys << rsign_pk;
}
if (!auth) return disconnect(ba, "Unauthorised");
ba.clear();
auth_sign = rsign_pk;
crypt.generateKeypair(my_pk, box_sk);
tba.clear();
tba << sign_pk << my_pk << box_pk;
PIByteArray sign = crypt.signMessage(tba, sign_sk);
tba << sign;
tba = crypt.crypt(tba, box_pk, box_sk);
state = AuthReply;
noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << tba << my_pk << noise;
sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return state;
}
if (state == AuthReply && rstate == PassRequest) {
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign, rsign_pk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> rsign_pk >> noise >> ctba;
if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key");
PIString ps;
PIByteArray ph;
passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar(0));
tba.clear();
tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba.clear();
state = PassRequest;
ba << (int)state << tba;
rsign = crypt.signMessage(ba, sign_sk);
ba << rsign;
return state;
}
if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) {
PIByteArray tba, ctba;
PIByteArray rsign;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
tba >> secret_key;
if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key");
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
if (state == Connected && rstate == Connected) {
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
// server side
if (role == Server) {
if (state == AuthProbe && rstate == AuthReply) {
if (ba.size() < sizeof(int)*4) return disconnect(ba, "invalid data size");
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign1, rsign2;
PIByteArray rsign_pk;
PIByteArray pk, mpk;
ba >> ctba >> pk >> noise >> rsign1;
bool ok = false;
tba = crypt.decrypt(ctba, pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
if (tba.size() < sizeof(int)*3) return disconnect(tba, "invalid data size");
tba >> rsign_pk >> box_pk >> mpk >> rsign2;
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
ba.clear();
ba << (int)rstate << ctba << box_pk << noise;
if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign");
ba.clear();
ba << rsign_pk << box_pk << my_pk;
if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign");
auth_sign = rsign_pk;
if (isAuthorizedKey(rsign_pk)) {
state = KeyExchange;
ba = createSKMessage();
return state;
} else {
ba.clear();
tba.clear();
state = PassRequest;
noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << sign_pk << noise << box_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba << (int)state << tba;
rsign1 = crypt.signMessage(ba, sign_sk);
ba << rsign1;
return state;
}
}
if (state == PassRequest && rstate == PassRequest) {
PIByteArray tba, ctba;
PIByteArray rsign_pk, rsign, mpk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> ctba >> mpk >> rsign_pk;
if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key");
bool auth = (ctba == pass_hash);
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
passwordCheck(auth);
if (!auth) {
// piSleep(1);
return disconnect(ba, "Invalid password");
}
state = KeyExchange;
ba = createSKMessage();
return state;
}
if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) {
ba.clear();
PIByteArray rinfo;
ba >> rinfo;
bool ok = false;
rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected;
connected(rinfo);
ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
return disconnect(ba, "invalid state " + PIString::fromNumber((int)state));
}
PIByteArray PIAuth::getSecretKey() {
if (state == Connected) return secret_key;
return PIByteArray();
}
PIByteArray PIAuth::generateSign(const PIByteArray & seed) {
PIByteArray pk, sk;
PICrypt::generateSignKeys(pk, sk, seed);
return sk;
}
PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
if (!error.isEmpty()) piCoutObj << error;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
secret_key.clear();
ba.clear();
state = NotConnected;
disconnected(error);
return state;
}
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
for (int i=0; i<auth_pkeys.size_s(); ++i) {
if (pkey == auth_pkeys[i]) return true;
}
return false;
}
PIByteArray PIAuth::createSKMessage() {
secret_key = crypt.generateKey();
PIByteArray tba;
PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << secret_key << noise;
tba = crypt.crypt(tba, box_pk, box_sk);
PIByteArray ret;
ret << (int)state << tba;
PIByteArray sign = crypt.signMessage(ret, sign_sk);
ret << sign;
return ret;
}
/*
PIP - Platform Independent Primitives
PIP Authentication API
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 "piauth.h"
#define PIAUTH_NOISE_MAX_SIZE 256
PIAuth::PIAuth(const PIByteArray & sign): PIObject() {
setName("Client");
role = Client;
state = NotConnected;
sign_sk = sign;
sign_pk = crypt.extractSignPublicKey(sign);
}
void PIAuth::setServerPassword(const PIString & ps) {
pass_hash = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
}
void PIAuth::stop() {
role = Client;
state = NotConnected;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
}
void PIAuth::startClient() {
role = Client;
state = AuthProbe;
}
PIByteArray PIAuth::startServer() {
setName("Server");
role = Server;
state = AuthProbe;
PIByteArray ba;
crypt.generateKeypair(my_pk, box_sk);
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE + 128);
ba << (int)state << custom_info << sign_pk << my_pk << noise;
PIByteArray sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return ba;
}
PIAuth::State PIAuth::receive(PIByteArray & ba) {
if (ba.size() < sizeof(int)) return disconnect(ba, "invalid data size");
State rstate;
int s;
ba >> s;
rstate = (State)s;
// if (state != rstate) return disconect(ba);
// client side
if (role == Client) {
if (state == AuthProbe && rstate == AuthProbe) {
if (ba.size() < sizeof(int) * 5) return disconnect(ba, "invalid data size");
PIByteArray rinfo;
PIByteArray rsign;
PIByteArray rsign_pk;
PIByteArray noise;
ba >> rinfo >> rsign_pk >> box_pk >> noise >> rsign;
if (rsign_pk.isEmpty() || box_pk.isEmpty() || rsign.isEmpty()) return disconnect(ba, "invalid key size");
PIByteArray tba;
tba << (int)rstate << rinfo << rsign_pk << box_pk << noise;
if (!crypt.verifySign(tba, rsign, rsign_pk)) return disconnect(ba, "Incorrect sign");
bool auth = false;
if (isAuthorizedKey(rsign_pk)) {
auth = true;
} else {
authorize(rinfo, &auth);
if (auth) auth_pkeys << rsign_pk;
}
if (!auth) return disconnect(ba, "Unauthorised");
ba.clear();
auth_sign = rsign_pk;
crypt.generateKeypair(my_pk, box_sk);
tba.clear();
tba << sign_pk << my_pk << box_pk;
PIByteArray sign = crypt.signMessage(tba, sign_sk);
tba << sign;
tba = crypt.crypt(tba, box_pk, box_sk);
state = AuthReply;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << tba << my_pk << noise;
sign = crypt.signMessage(ba, sign_sk);
ba << sign;
return state;
}
if (state == AuthReply && rstate == PassRequest) {
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign, rsign_pk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> rsign_pk >> noise >> ctba;
if (rsign_pk != auth_sign || ctba != my_pk) return disconnect(ba, "Invalid public key");
PIString ps;
PIByteArray ph;
passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar());
tba.clear();
tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba.clear();
state = PassRequest;
ba << (int)state << tba;
rsign = crypt.signMessage(ba, sign_sk);
ba << rsign;
return state;
}
if ((state == AuthReply && rstate == KeyExchange) || (state == PassRequest && rstate == KeyExchange)) {
PIByteArray tba, ctba;
PIByteArray rsign;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
tba >> secret_key;
if (secret_key.size() != crypt.sizeKey()) return disconnect(ba, "Invalid key");
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
return state;
}
if (state == Connected && rstate == Connected) {
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
// server side
if (role == Server) {
if (state == AuthProbe && rstate == AuthReply) {
if (ba.size() < sizeof(int) * 4) return disconnect(ba, "invalid data size");
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign1, rsign2;
PIByteArray rsign_pk;
PIByteArray pk, mpk;
ba >> ctba >> pk >> noise >> rsign1;
bool ok = false;
tba = crypt.decrypt(ctba, pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
if (tba.size() < sizeof(int) * 3) return disconnect(tba, "invalid data size");
tba >> rsign_pk >> box_pk >> mpk >> rsign2;
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
ba.clear();
ba << (int)rstate << ctba << box_pk << noise;
if (!crypt.verifySign(ba, rsign1, rsign_pk)) return disconnect(ba, "Incorrect sign");
ba.clear();
ba << rsign_pk << box_pk << my_pk;
if (!crypt.verifySign(ba, rsign2, rsign_pk)) return disconnect(ba, "Incorrect sign");
auth_sign = rsign_pk;
if (isAuthorizedKey(rsign_pk)) {
state = KeyExchange;
ba = createSKMessage();
return state;
} else {
ba.clear();
tba.clear();
state = PassRequest;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
tba << sign_pk << noise << box_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba << (int)state << tba;
rsign1 = crypt.signMessage(ba, sign_sk);
ba << rsign1;
return state;
}
}
if (state == PassRequest && rstate == PassRequest) {
PIByteArray tba, ctba;
PIByteArray rsign_pk, rsign, mpk;
ba >> ctba >> rsign;
bool ok = false;
tba = crypt.decrypt(ctba, box_pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
ba.clear();
ba << (int)rstate << ctba;
if (!crypt.verifySign(ba, rsign, auth_sign)) return disconnect(ba, "Incorrect sign");
ctba.clear();
tba >> ctba >> mpk >> rsign_pk;
if (rsign_pk != auth_sign || mpk != sign_pk) return disconnect(ba, "Invalid public key");
bool auth = (ctba == pass_hash);
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
passwordCheck(auth);
if (!auth) {
// piSleep(1);
return disconnect(ba, "Invalid password");
}
state = KeyExchange;
ba = createSKMessage();
return state;
}
if ((state == KeyExchange && rstate == Connected) || (state == Connected && rstate == Connected)) {
ba.clear();
PIByteArray rinfo;
ba >> rinfo;
bool ok = false;
rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected;
connected(PIString::fromUTF8(rinfo));
ba << (int)state << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
return disconnect(ba, "invalid state " + PIString::fromNumber((int)state));
}
PIByteArray PIAuth::getSecretKey() {
if (state == Connected) return secret_key;
return PIByteArray();
}
PIByteArray PIAuth::generateSign(const PIByteArray & seed) {
PIByteArray pk, sk;
PICrypt::generateSignKeys(pk, sk, seed);
return sk;
}
PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
if (!error.isEmpty()) piCoutObj << error;
auth_sign.clear();
box_sk.clear();
box_pk.clear();
my_pk.clear();
secret_key.clear();
ba.clear();
state = NotConnected;
disconnected(error);
return state;
}
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
for (int i = 0; i < auth_pkeys.size_s(); ++i) {
if (pkey == auth_pkeys[i]) return true;
}
return false;
}
PIByteArray PIAuth::createSKMessage() {
secret_key = crypt.generateKey();
PIByteArray tba;
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
tba << secret_key << noise;
tba = crypt.crypt(tba, box_pk, box_sk);
PIByteArray ret;
ret << (int)state << tba;
PIByteArray sign = crypt.signMessage(ret, sign_sk);
ret << sign;
return ret;
}

View File

@@ -1,435 +1,457 @@
/*
PIP - Platform Independent Primitives
Cryptographic class using lib Sodium
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 "picrypt.h"
#ifdef PIP_CRYPT
# 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";
const int hash_def_key_size = 9;
PICrypt::PICrypt() {
#ifdef PIP_CRYPT
if (!init()) piCout << "[PICrypt]" << "Error while initialize sodium!";
nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(key_.data(), key_.size());
randombytes_buf(nonce_.data(), nonce_.size());
#else
PICRYPT_DISABLED_WARNING
#endif
}
bool PICrypt::setKey(const PIByteArray & _key) {
if (_key.size() != key_.size()) return false;
key_ = _key;
return true;
}
PIByteArray PICrypt::setKey(const PIString & secret) {
PIByteArray hash;
#ifdef PIP_CRYPT
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 ret;
#ifdef PIP_CRYPT
ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(nonce_.data(), nonce_.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data());
ret.append(nonce_);
#endif
return ret;
}
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (key.size() != crypto_secretbox_KEYBYTES)
key.resize(crypto_secretbox_KEYBYTES, ' ');
//return PIByteArray();
if (!init()) return ret;
PIByteArray n;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
n.resize(crypto_secretbox_NONCEBYTES);
randombytes_buf(n.data(), n.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data());
ret.append(n);
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool *ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
ret.resize(crypt_data.size() - nonce_.size() - crypto_secretbox_MACBYTES);
memcpy(nonce_.data(), crypt_data.data(crypt_data.size() - nonce_.size()), nonce_.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - nonce_.size(), nonce_.data(), key_.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
}
#endif
if (ok) *ok = true;
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool *ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
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();
}
if (!init()) return ret;
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok) *ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::hash(const PIString & secret) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
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);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::hash(const PIByteArray & data) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), (const uchar*)hash_def_key, hash_def_key_size);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
size_t PICrypt::sizeHash() {
#ifdef PIP_CRYPT
return crypto_generichash_BYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
ullong PICrypt::shorthash(const PIString& s, PIByteArray key) {
ullong hash = 0;
#ifdef PIP_CRYPT
if (crypto_shorthash_BYTES != sizeof(hash)) piCout << "[PICrypt]" << "internal error: bad hash size";
if (!init()) return hash;
if (key.size() != crypto_shorthash_KEYBYTES) {
piCout << "[PICrypt]" << "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
key.resize(crypto_shorthash_KEYBYTES, 0);
}
PIByteArray in(s.data(), s.size());
crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::generateKey() {
PIByteArray hash;
#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 hash;
#ifdef PIP_CRYPT
if (!init() || size <= 0) return hash;
hash.resize(size);
randombytes_buf(hash.data(), hash.size());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
size_t PICrypt::sizeKey() {
#ifdef PIP_CRYPT
return crypto_secretbox_KEYBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
size_t PICrypt::sizeCrypt() {
#ifdef PIP_CRYPT
return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_keypair(public_key.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT
if (!init() || seed.isEmpty()) return;
public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) {
PIByteArray pk;
#ifdef PIP_CRYPT
if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk;
pk.resize(crypto_sign_PUBLICKEYBYTES);
crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return pk;
}
PIByteArray PICrypt::signMessage(const PIByteArray & data, PIByteArray secret_key) {
PIByteArray sign;
#ifdef PIP_CRYPT
if (!init()) return sign;
sign.resize(crypto_sign_BYTES);
crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return sign;
}
bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key) {
#ifdef PIP_CRYPT
if (!init()) return false;
return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0);
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_keypair(public_key.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES)
return ret;
if (secret_key.size() != crypto_box_SECRETKEYBYTES)
return ret;
PIByteArray n;
ret.resize(data.size() + crypto_box_MACBYTES);
n.resize(crypto_box_NONCEBYTES);
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)
return PIByteArray();
ret.append(n);
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
if (ok) *ok = false;
return ret;
}
if (secret_key.size() != crypto_box_SECRETKEYBYTES) {
if (ok) *ok = false;
return ret;
}
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) {
if (ok) *ok = false;
return ret;
}
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok) *ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray & seed) {
#ifdef crypto_pwhash_ALG_ARGON2I13
// char out[crypto_pwhash_STRBYTES];
PIByteArray pass = password.toUTF8();
PIByteArray n = hash(seed);
PIByteArray ph;
ph.resize(crypto_box_SEEDBYTES);
n.resize(crypto_pwhash_SALTBYTES);
// randombytes_buf(n.data(), n.size());
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data());
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);
//crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate());
pass.fill(0);
if (r != 0) return PIByteArray();
return ph;
// PIByteArray ret;
// ret << ph << n << crypto_pwhash_argon2i_opslimit_moderate() << crypto_pwhash_argon2i_memlimit_moderate();
// return ret;
#else
return PIByteArray();
#endif
}
PIString PICrypt::version() {
#ifdef PIP_CRYPT
return SODIUM_VERSION_STRING;
#else
return PIString();
#endif
}
bool PICrypt::init() {
#ifdef PIP_CRYPT
static bool inited = false;
if (inited) return true;
//piCout << "[PICrypt]" << "init ...";
inited = sodium_init();
if (!inited)
inited = sodium_init();
//piCout << "[PICrypt]" << "init" << inited;
return inited;
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}
/*
PIP - Platform Independent Primitives
Cryptographic class using lib Sodium
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 "picrypt.h"
#ifdef PIP_CRYPT
# 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";
const int hash_def_key_size = 9;
PICrypt::PICrypt() {
#ifdef PIP_CRYPT
if (!init())
piCout << "[PICrypt]"
<< "Error while initialize sodium!";
nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(key_.data(), key_.size());
randombytes_buf(nonce_.data(), nonce_.size());
#else
PICRYPT_DISABLED_WARNING
#endif
}
bool PICrypt::setKey(const PIByteArray & _key) {
if (_key.size() != key_.size()) return false;
key_ = _key;
return true;
}
PIByteArray PICrypt::setKey(const PIString & secret) {
PIByteArray hash;
#ifdef PIP_CRYPT
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 ret;
#ifdef PIP_CRYPT
ret.resize(data.size() + crypto_secretbox_MACBYTES);
randombytes_buf(nonce_.data(), nonce_.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), nonce_.data(), key_.data());
ret.append(nonce_);
#endif
return ret;
}
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' ');
// return PIByteArray();
if (!init()) return ret;
PIByteArray n;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
n.resize(crypto_secretbox_NONCEBYTES);
randombytes_buf(n.data(), n.size());
crypto_secretbox_easy(ret.data(), data.data(), data.size(), n.data(), key.data());
ret.append(n);
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
return PIByteArray();
}
ret.resize(crypt_data.size() - nonce_.size() - crypto_secretbox_MACBYTES);
memcpy(nonce_.data(), crypt_data.data(crypt_data.size() - nonce_.size()), nonce_.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - nonce_.size(), nonce_.data(), key_.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
}
#endif
if (ok) *ok = true;
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
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();
}
if (!init()) return ret;
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_secretbox_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), key.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok)
*ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::hash(const PIString & secret) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
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);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::hash(const PIByteArray & data) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), (const uchar *)hash_def_key, hash_def_key_size);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char * key, size_t keylen) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), key, keylen);
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
size_t PICrypt::sizeHash() {
#ifdef PIP_CRYPT
return crypto_generichash_BYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
ullong PICrypt::shorthash(const PIString & s, PIByteArray key) {
ullong hash = 0;
#ifdef PIP_CRYPT
if (crypto_shorthash_BYTES != sizeof(hash))
piCout << "[PICrypt]"
<< "internal error: bad hash size";
if (!init()) return hash;
if (key.size() != crypto_shorthash_KEYBYTES) {
piCout << "[PICrypt]"
<< "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
key.resize(crypto_shorthash_KEYBYTES, 0);
}
PIByteArray in(s.data(), s.size());
crypto_shorthash((uchar *)&hash, in.data(), in.size(), key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
PIByteArray PICrypt::generateKey() {
PIByteArray hash;
#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 hash;
#ifdef PIP_CRYPT
if (!init() || size <= 0) return hash;
hash.resize(size);
randombytes_buf(hash.data(), hash.size());
#else
PICRYPT_DISABLED_WARNING
#endif
return hash;
}
size_t PICrypt::sizeKey() {
#ifdef PIP_CRYPT
return crypto_secretbox_KEYBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
size_t PICrypt::sizeCrypt() {
#ifdef PIP_CRYPT
return crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
#else
PICRYPT_DISABLED_WARNING
#endif
return 0;
}
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_keypair(public_key.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
void PICrypt::generateSignKeys(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT
if (!init() || seed.isEmpty()) return;
public_key.resize(crypto_sign_PUBLICKEYBYTES);
secret_key.resize(crypto_sign_SECRETKEYBYTES);
crypto_sign_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
PIByteArray PICrypt::extractSignPublicKey(const PIByteArray & secret_key) {
PIByteArray pk;
#ifdef PIP_CRYPT
if (!init() || secret_key.size() != crypto_sign_SECRETKEYBYTES) return pk;
pk.resize(crypto_sign_PUBLICKEYBYTES);
crypto_sign_ed25519_sk_to_pk(pk.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return pk;
}
PIByteArray PICrypt::signMessage(const PIByteArray & data, PIByteArray secret_key) {
PIByteArray sign;
#ifdef PIP_CRYPT
if (!init()) return sign;
sign.resize(crypto_sign_BYTES);
crypto_sign_detached(sign.data(), 0, data.data(), data.size(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
return sign;
}
bool PICrypt::verifySign(const PIByteArray & data, const PIByteArray & signature, PIByteArray public_key) {
#ifdef PIP_CRYPT
if (!init()) return false;
return (crypto_sign_verify_detached(signature.data(), data.data(), data.size(), public_key.data()) == 0);
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_keypair(public_key.data(), secret_key.data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
void PICrypt::generateKeypair(PIByteArray & public_key, PIByteArray & secret_key, const PIByteArray & seed) {
#ifdef PIP_CRYPT
if (!init()) return;
public_key.resize(crypto_box_PUBLICKEYBYTES);
secret_key.resize(crypto_box_SECRETKEYBYTES);
crypto_box_seed_keypair(public_key.data(), secret_key.data(), hash(seed).data());
#else
PICRYPT_DISABLED_WARNING
#endif
}
PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_key, const PIByteArray & secret_key) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) return ret;
if (secret_key.size() != crypto_box_SECRETKEYBYTES) return ret;
PIByteArray n;
ret.resize(data.size() + crypto_box_MACBYTES);
n.resize(crypto_box_NONCEBYTES);
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) return PIByteArray();
ret.append(n);
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray & public_key, const PIByteArray & secret_key, bool * ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) {
if (ok) *ok = false;
return ret;
}
if (secret_key.size() != crypto_box_SECRETKEYBYTES) {
if (ok) *ok = false;
return ret;
}
if (crypt_data.size() < crypto_box_NONCEBYTES + crypto_box_MACBYTES) {
if (ok) *ok = false;
return ret;
}
PIByteArray n;
n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) !=
0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok)
*ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
return ret;
}
PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray & seed) {
#ifdef crypto_pwhash_ALG_ARGON2I13
// char out[crypto_pwhash_STRBYTES];
PIByteArray pass = password.toUTF8();
PIByteArray n = hash(seed);
PIByteArray ph;
ph.resize(crypto_box_SEEDBYTES);
n.resize(crypto_pwhash_SALTBYTES);
// randombytes_buf(n.data(), n.size());
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data());
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);
// crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(),
// crypto_pwhash_argon2i_memlimit_moderate());
pass.fill(0);
if (r != 0) return PIByteArray();
return ph;
// PIByteArray ret;
// ret << ph << n << crypto_pwhash_argon2i_opslimit_moderate() << crypto_pwhash_argon2i_memlimit_moderate();
// return ret;
#else
return PIByteArray();
#endif
}
PIString PICrypt::version() {
#ifdef PIP_CRYPT
return SODIUM_VERSION_STRING;
#else
return PIString();
#endif
}
bool PICrypt::init() {
#ifdef PIP_CRYPT
static bool inited = false;
if (inited) return true;
// piCout << "[PICrypt]" << "init ...";
inited = sodium_init();
if (!inited) inited = sodium_init();
// piCout << "[PICrypt]" << "init" << inited;
return inited;
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}

View File

@@ -1,34 +1,48 @@
/*
PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations
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 "pifft.h"
#include "pifft_p.h"
#define _PIFFTW_CPP(type) \
_PIFFTW_P_##type##_::_PIFFTW_P_##type##_() {impl = new PIFFTW_Private<type>();;} \
_PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() {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(double)
_PIFFTW_CPP(ldouble)
/*
PIP - Platform Independent Primitives
Class for FFT, IFFT and Hilbert transformations
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 "pifft.h"
#include "pifft_p.h"
#define _PIFFTW_CPP(type) \
_PIFFTW_P_##type##_::_PIFFTW_P_##type##_() { \
impl = new PIFFTW_Private<type>(); \
; \
} \
_PIFFTW_P_##type##_::~_PIFFTW_P_##type##_() { \
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(double)
_PIFFTW_CPP(ldouble)

View File

@@ -1,180 +1,247 @@
/*! @file pifft_p.h
* @brief Class for FFT, IFFT and Hilbert transformations
*/
/*
PIP - Platform Independent Primitives
Private header for fftw3
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/>.
*/
#ifndef PIFFT_P_H
#define PIFFT_P_H
#include "pivector.h"
#include "picout.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h"
#else
# define FFTW_FORWARD 0
# define FFTW_BACKWARD 0
# define FFTW_ESTIMATE 0
# define FFTW_MEASURE 0
#endif
template <typename T>
class PIFFTW_Private
{
public:
explicit PIFFTW_Private() {
plan = 0;
//#ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
//#endif
p_makeThreadSafe();
}
~PIFFTW_Private() {p_destroyPlan(plan);}
const PIVector<complex<T> > & calcFFT(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T> > & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real);
}
p_executePlan_r2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T> > & calcFFTinverse(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size());
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
enum FFT_Operation {fo_real, fo_complex, fo_inverse};
void preparePlan(int size, int op) {
p_inr.clear();
p_in.clear();
p_out.clear();
switch ((FFT_Operation)op) {
case fo_real:
p_inr.resize(size);
p_out.resize(size);
p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_complex:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_inverse:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
default:
size = 0;
break;
}
prepare = PlanParams(size, (FFT_Operation)op);
}
inline void p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {}
inline void p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {}
inline void p_executePlan(void * plan) {}
inline void p_executePlan_c2c(void * plan, const void * in, void * out) {}
inline void p_executePlan_r2c(void * plan, const void * in, void * out) {}
inline void p_destroyPlan(void *& plan) {}
inline void p_makeThreadSafe() {}
struct PlanParams {
PlanParams() {size = 0; op = fo_complex;}
PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;}
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 !(*this == v);}
int size;
FFT_Operation op;
};
PIVector<complex<T> > p_in;
PIVector<T> p_inr;
PIVector<complex<T> > p_out;
void * plan;
PlanParams prepare;
};
#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) {
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, 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_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<> 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
template<> inline void PIFFTW_Private<float>::p_makeThreadSafe() {fftwf_make_planner_thread_safe();}
# endif
#endif // PIP_FFTWf
#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) {
plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, 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_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<> 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
template<> inline void PIFFTW_Private<double>::p_makeThreadSafe() {fftw_make_planner_thread_safe();}
# endif
#endif // PIP_FFTW
#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) {
plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, 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_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<> 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
template<> inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {fftwl_make_planner_thread_safe();}
# endif
#endif // PIP_FFTWl
#endif // PIFFT_H
/*! \file pifft_p.h
* \brief Class for FFT, IFFT and Hilbert transformations
*/
/*
PIP - Platform Independent Primitives
Private header for fftw3
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/>.
*/
#ifndef PIFFT_P_H
#define PIFFT_P_H
#include "picout.h"
#include "pivector.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h"
#else
# define FFTW_FORWARD 0
# define FFTW_BACKWARD 0
# define FFTW_ESTIMATE 0
# define FFTW_MEASURE 0
#endif
template<typename T>
class PIFFTW_Private {
public:
explicit PIFFTW_Private() {
plan = 0;
// #ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
// #endif
p_makeThreadSafe();
}
~PIFFTW_Private() { p_destroyPlan(plan); }
const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) {
if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real);
}
p_executePlan_r2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
enum FFT_Operation {
fo_real,
fo_complex,
fo_inverse
};
void preparePlan(int size, int op) {
p_inr.clear();
p_in.clear();
p_out.clear();
switch ((FFT_Operation)op) {
case fo_real:
p_inr.resize(size);
p_out.resize(size);
p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_complex:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
case fo_inverse:
p_in.resize(size);
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
default: size = 0; break;
}
prepare = PlanParams(size, (FFT_Operation)op);
}
inline void p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {}
inline void p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {}
inline void p_executePlan(void * plan) {}
inline void p_executePlan_c2c(void * plan, const void * in, void * out) {}
inline void p_executePlan_r2c(void * plan, const void * in, void * out) {}
inline void p_destroyPlan(void *& plan) {}
inline void p_makeThreadSafe() {}
struct PlanParams {
PlanParams() {
size = 0;
op = fo_complex;
}
PlanParams(int size_, FFT_Operation op_) {
size = size_;
op = op_;
}
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 !(*this == v); }
int size;
FFT_Operation op;
};
PIVector<complex<T>> p_in;
PIVector<T> p_inr;
PIVector<complex<T>> p_out;
void * plan;
PlanParams prepare;
};
#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) {
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, 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_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<>
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
template<>
inline void PIFFTW_Private<float>::p_makeThreadSafe() {
fftwf_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTWf
#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) {
plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, 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_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<>
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
template<>
inline void PIFFTW_Private<double>::p_makeThreadSafe() {
fftw_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTW
#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) {
plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, 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_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<>
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
template<>
inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {
fftwl_make_planner_thread_safe();
}
# endif
#endif // PIP_FFTWl
#endif // PIFFT_H

View File

@@ -1,268 +1,269 @@
/*
PIP - Platform Independent Primitives
Broadcast for all interfaces, including loopback
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 "pibroadcast.h"
/** \class PIBroadcast
* @brief Broadcast for all interfaces, including loopback
*
* \section PIBroadcast_synopsis Synopsis
* %PIBroadcast used as multichannel IO device. It can use
* multicast, broadcast and loopback ethernet channels to
* send/receive packets. \a send() function send packet to
* all initialized ethernets. \a receiveEvent() raised on
* packet received by any ethernet. All multi/broadcast
* ethernets created for all current addresses, obtained
* by \a PIEthernets::allAddresses().
*
* * \a Multicast ethernets use \a multicastGroup() and \a multicastPort()
* * \a Broadcast ethernets use \a broadcastPort()
* * \a Loopback ethernet use \a loopbackPortsCount() started from \a loopbackPort()
*
* %PIBroadcast starts thread, which every 3 seconds check if
* current \a PIEthernet::allAddresses() was changed and call
* \a reinit() if it necessary.
*
*/
#define MULTICAST_TTL 4
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
_channels = All;
eth_lo = 0;
mcast_address.set("232.13.3.14", 14100);
lo_port = 14200;
lo_pcnt = 5;
_started = false;
_send_only = send_only;
_reinit = true;
//initMcast(PIEthernet::allAddresses());
PIThread::start(3000);
}
PIBroadcast::~PIBroadcast() {
PIThread::stop();
mcast_mutex.unlock();
destroyAll();
}
void PIBroadcast::setChannels(PIBroadcast::Channels ch) {
PIMutexLocker ml(mcast_mutex);
_channels = ch;
_reinit = true;
}
void PIBroadcast::setMulticastGroup(const PIString & mg) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setIP(mg);
_reinit = true;
}
void PIBroadcast::setMulticastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setPort(port);
_reinit = true;
}
void PIBroadcast::setMulticastAddress(const PIEthernet::Address & addr) {
PIMutexLocker ml(mcast_mutex);
mcast_address = addr;
_reinit = true;
}
void PIBroadcast::setBroadcastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
bcast_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
lo_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPortsCount(int count) {
PIMutexLocker ml(mcast_mutex);
lo_pcnt = count;
_reinit = true;
}
void PIBroadcast::destroyAll() {
piForeach (PIEthernet * e, eth_mcast) {
e->stopThreadedRead();
delete e;
}
eth_mcast.clear();
if (eth_lo) {
eth_lo->stopThreadedRead();
delete eth_lo;
eth_lo = 0;
}
}
void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
PIMutexLocker ml(mcast_mutex);
destroyAll();
_reinit = false;
prev_al = al;
al.removeAll(PIEthernet::Address("127.0.0.1"));
al << mcast_address;
eth_mcast.clear();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
piForeachC (PIEthernet::Address & a, al) {
PIEthernet * ce = 0;
//piCout << "mcast try" << a;
if (_channels[Multicast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(0);
ce->setSendAddress(mcast_address);
ce->setMulticastTTL(MULTICAST_TTL);
if (!_send_only) {
ce->setReadAddress(a.ipString(), mcast_address.port());
ce->joinMulticastGroup(mcast_address.ipString());
//piCout << "mcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECTU(ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
if (_channels[Broadcast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(PIEthernet::Broadcast);
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
PIEthernet::Address nm((cint == 0) ? "255.255.255.0" : cint->netmask);
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
if (!_send_only) {
ce->setReadAddress(PIEthernet::Address(a.ip(), bcast_port));
//piCout << "bcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECTU(ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
}
if (_channels[Loopback]) {
eth_lo = new PIEthernet();
eth_lo->setDebug(false);
eth_lo->setName("PIMulticast_loopback");
if (!_send_only) {
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
if (eth_lo->open()) {
//piCout << "bind local to" << (lo_port + i);
break;
}
}
}
}
}
void PIBroadcast::send(const PIByteArray & data) {
PIByteArray cd = cryptData(data);
if (cd.isEmpty()) return;
PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast)
e->send(cd);
if (eth_lo) {
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->send("127.0.0.1", lo_port + i, cd);
}
}
}
void PIBroadcast::startRead() {
if (_send_only) return;
PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast)
e->startThreadedRead();
if (eth_lo)
eth_lo->startThreadedRead();
_started = true;
}
void PIBroadcast::stopRead() {
PIMutexLocker ml(mcast_mutex);
piForeach (PIEthernet * e, eth_mcast)
e->stopThreadedRead();
if (eth_lo)
eth_lo->stopThreadedRead();
_started = false;
}
void PIBroadcast::reinit() {
initAll(PIEthernet::allAddresses());
if (_started)
startRead();
}
void PIBroadcast::mcastRead(uchar * data, int size) {
PIByteArray cd = decryptData(PIByteArray(data, size));
if (cd.isEmpty()) return;
received(cd);
receiveEvent(cd);
}
void PIBroadcast::run() {
PIVector<PIEthernet::Address> al = PIEthernet::allAddresses();
mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al);
mcast_mutex.unlock();
if (ac || r)
reinit();
if (ac)
addressesChanged();
}
/*
PIP - Platform Independent Primitives
Broadcast for all interfaces, including loopback
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 "pibroadcast.h"
/** \class PIBroadcast
* \brief Broadcast for all interfaces, including loopback
*
* \section PIBroadcast_synopsis Synopsis
* %PIBroadcast used as multichannel IO device. It can use
* multicast, broadcast and loopback ethernet channels to
* send/receive packets. \a send() function send packet to
* all initialized ethernets. \a receiveEvent() raised on
* packet received by any ethernet. All multi/broadcast
* ethernets created for all current addresses, obtained
* by \a PIEthernets::allAddresses().
*
* * \a Multicast ethernets use \a multicastGroup() and \a multicastPort()
* * \a Broadcast ethernets use \a broadcastPort()
* * \a Loopback ethernet use \a loopbackPortsCount() started from \a loopbackPort()
*
* %PIBroadcast starts thread, which every 3 seconds check if
* current \a PIEthernet::allAddresses() was changed and call
* \a reinit() if it necessary.
*
*/
#define MULTICAST_TTL 4
PIBroadcast::PIBroadcast(bool send_only): PIThread(), PIEthUtilBase() {
_channels = All;
eth_lo = 0;
mcast_address.set("232.13.3.14", 14100);
lo_port = 14200;
lo_pcnt = 5;
_started = false;
_send_only = send_only;
_reinit = true;
}
PIBroadcast::~PIBroadcast() {
PIThread::stop();
mcast_mutex.unlock();
destroyAll();
}
void PIBroadcast::setChannels(PIBroadcast::Channels ch) {
PIMutexLocker ml(mcast_mutex);
_channels = ch;
_reinit = true;
}
void PIBroadcast::setMulticastGroup(const PIString & mg) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setIP(mg);
_reinit = true;
}
void PIBroadcast::setMulticastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
mcast_address.setPort(port);
_reinit = true;
}
void PIBroadcast::setMulticastAddress(const PINetworkAddress & addr) {
PIMutexLocker ml(mcast_mutex);
mcast_address = addr;
_reinit = true;
}
void PIBroadcast::setBroadcastPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
bcast_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPort(ushort port) {
PIMutexLocker ml(mcast_mutex);
lo_port = port;
_reinit = true;
}
void PIBroadcast::setLoopbackPortsCount(int count) {
PIMutexLocker ml(mcast_mutex);
lo_pcnt = count;
_reinit = true;
}
void PIBroadcast::destroyAll() {
piForeach(PIEthernet * e, eth_mcast) {
e->stopThreadedRead();
delete e;
}
eth_mcast.clear();
if (eth_lo) {
eth_lo->stopThreadedRead();
delete eth_lo;
eth_lo = 0;
}
}
void PIBroadcast::initAll(PIVector<PINetworkAddress> al) {
PIMutexLocker ml(mcast_mutex);
destroyAll();
_reinit = false;
prev_al = al;
al.removeAll(PINetworkAddress("127.0.0.1"));
al << mcast_address;
eth_mcast.clear();
PIEthernet::InterfaceList ifaces = PIEthernet::interfaces();
piForeachC(PINetworkAddress & a, al) {
PIEthernet * ce = 0;
// piCout << "mcast try" << a;
if (_channels[Multicast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(0);
ce->setSendAddress(mcast_address);
ce->setMulticastTTL(MULTICAST_TTL);
if (!_send_only) {
ce->setReadAddress(a.ipString(), mcast_address.port());
ce->joinMulticastGroup(mcast_address.ipString());
// piCout << "mcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
if (_channels[Broadcast]) {
ce = new PIEthernet();
ce->setDebug(false);
ce->setName("PIMulticast_" + a.toString());
ce->setParameters(PIEthernet::Broadcast);
const PIEthernet::Interface * cint = ifaces.getByAddress(a.ipString());
PINetworkAddress nm((cint == 0) ? "255.255.255.0" : cint->netmask);
ce->setSendAddress(PIEthernet::getBroadcast(a, nm).ipString(), bcast_port);
if (!_send_only) {
ce->setReadAddress(PINetworkAddress(a.ip(), bcast_port));
// piCout << "bcast " << ce->readAddress() << ce->sendAddress();
if (ce->open()) {
eth_mcast << ce;
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
} else {
delete ce;
}
} else {
eth_mcast << ce;
}
}
}
if (_channels[Loopback]) {
eth_lo = new PIEthernet();
eth_lo->setDebug(false);
eth_lo->setName("PIMulticast_loopback");
if (!_send_only) {
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
CONNECT2(void, const uchar *, ssize_t, eth_lo, threadedReadEvent, this, mcastRead);
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
if (eth_lo->open()) {
// piCout << "bind local to" << (lo_port + i);
break;
}
}
}
}
}
void PIBroadcast::send(const PIByteArray & data) {
if (!isRunning()) {
reinit();
PIThread::start(3000);
}
PIByteArray cd = cryptData(data);
if (cd.isEmpty()) return;
PIMutexLocker ml(mcast_mutex);
piForeach(PIEthernet * e, eth_mcast)
e->send(cd);
if (eth_lo) {
for (int i = 0; i < lo_pcnt; ++i) {
eth_lo->send("127.0.0.1", lo_port + i, cd);
}
}
}
void PIBroadcast::startRead() {
if (!isRunning()) {
_started = false;
reinit();
PIThread::start(3000);
}
if (_send_only) return;
PIMutexLocker ml(mcast_mutex);
piForeach(PIEthernet * e, eth_mcast)
e->startThreadedRead();
if (eth_lo) eth_lo->startThreadedRead();
_started = true;
}
void PIBroadcast::stopRead() {
if (isRunning()) stop();
PIMutexLocker ml(mcast_mutex);
piForeach(PIEthernet * e, eth_mcast)
e->stopThreadedRead();
if (eth_lo) eth_lo->stopThreadedRead();
_started = false;
}
void PIBroadcast::reinit() {
initAll(PIEthernet::allAddresses());
if (_started) startRead();
}
void PIBroadcast::mcastRead(const uchar * data, ssize_t size) {
PIByteArray cd = decryptData(PIByteArray(data, size));
if (cd.isEmpty()) return;
received(cd);
receiveEvent(cd);
}
void PIBroadcast::run() {
PIVector<PINetworkAddress> al = PIEthernet::allAddresses();
mcast_mutex.lock();
bool r = _reinit, ac = (al != prev_al);
mcast_mutex.unlock();
if (ac || r) reinit();
if (ac) addressesChanged();
}

View File

@@ -1,121 +1,120 @@
/*
PIP - Platform Independent Primitives
Base class for ethernet utils
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 "piethutilbase.h"
#ifdef PIP_CRYPT
# include "picrypt.h"
#endif
/** \class PIEthUtilBase
* @brief Base class for ethernet utils
*
* \section PIEthUtilBase_synopsis Synopsis
* %PIEthUtilBase provides crypt layer for derived classes:
* \a PIStreamPacker and \a PIBroadcast. All input and output
* (sended and received) data can be decrypted/encrypted by this layer.
*
* By default crypt layer is disabled.
*
* You can separetely enable it and set ready-to-use
* key by \a setCryptEnabled() and \a setCryptKey(). Or you can
* use \a createCryptKey() to generate key from your passphrase
* and automatic enable crypt layer.
*
* \note To use crypt layer, PIP should be built with crypt module,
* otherwise your in/out data will be lost.
*
* You can use this class as base for your own classes. Use \a cryptData()
* and \a decryptData() when send and receive your data.
*
*/
PIEthUtilBase::PIEthUtilBase() {
_crypt = false;
}
PIEthUtilBase::~PIEthUtilBase() {
}
void PIEthUtilBase::setCryptEnabled(bool on) {
_crypt = on;
}
void PIEthUtilBase::cryptEnable() {
setCryptEnabled(true);
}
void PIEthUtilBase::cryptDisable() {
setCryptEnabled(false);
}
bool PIEthUtilBase::isCryptEnabled() const {
return _crypt;
}
void PIEthUtilBase::setCryptKey(const PIByteArray & k) {
_key = k;
setCryptEnabled(true);
}
void PIEthUtilBase::createCryptKey(const PIString & k) {
#ifdef PIP_CRYPT
_key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash(k);
#else
piCout << "[PIEthUtilBase] PICrypt wasn`t built!";
#endif
_crypt = true;
}
PIByteArray PIEthUtilBase::cryptKey() const {
return _key;
}
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) {
if (!_crypt) return data;
return
#ifdef PIP_CRYPT
PICrypt::crypt(data, _key);
#else
PIByteArray();
#endif
}
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
if (!_crypt) return data;
#ifdef PIP_CRYPT
bool ok = false;
PIByteArray ret = PICrypt::decrypt(data, _key, &ok);
if (!ok) return PIByteArray();
return ret;
#else
return PIByteArray();
#endif
}
/*
PIP - Platform Independent Primitives
Base class for ethernet utils
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 "piethutilbase.h"
#ifdef PIP_CRYPT
# include "picrypt.h"
#endif
/** \class PIEthUtilBase
* \brief Base class for ethernet utils
*
* \section PIEthUtilBase_synopsis Synopsis
* %PIEthUtilBase provides crypt layer for derived classes:
* \a PIStreamPacker and \a PIBroadcast. All input and output
* (sended and received) data can be decrypted/encrypted by this layer.
*
* By default crypt layer is disabled.
*
* You can separetely enable it and set ready-to-use
* key by \a setCryptEnabled() and \a setCryptKey(). Or you can
* use \a createCryptKey() to generate key from your passphrase
* and automatic enable crypt layer.
*
* \note To use crypt layer, PIP should be built with crypt module,
* otherwise your in/out data will be lost.
*
* You can use this class as base for your own classes. Use \a cryptData()
* and \a decryptData() when send and receive your data.
*
*/
PIEthUtilBase::PIEthUtilBase() {
_crypt = false;
}
PIEthUtilBase::~PIEthUtilBase() {}
void PIEthUtilBase::setCryptEnabled(bool on) {
_crypt = on;
}
void PIEthUtilBase::cryptEnable() {
setCryptEnabled(true);
}
void PIEthUtilBase::cryptDisable() {
setCryptEnabled(false);
}
bool PIEthUtilBase::isCryptEnabled() const {
return _crypt;
}
void PIEthUtilBase::setCryptKey(const PIByteArray & k) {
_key = k;
setCryptEnabled(true);
}
void PIEthUtilBase::createCryptKey(const PIString & k) {
#ifdef PIP_CRYPT
_key = PICrypt::hash("sodium_bug");
_key = PICrypt::hash(k);
#else
piCout << "[PIEthUtilBase] PICrypt wasn`t built!";
#endif
_crypt = true;
}
PIByteArray PIEthUtilBase::cryptKey() const {
return _key;
}
PIByteArray PIEthUtilBase::cryptData(const PIByteArray & data) {
if (!_crypt) return data;
return
#ifdef PIP_CRYPT
PICrypt::crypt(data, _key);
#else
PIByteArray();
#endif
}
PIByteArray PIEthUtilBase::decryptData(const PIByteArray & data) {
if (!_crypt) return data;
#ifdef PIP_CRYPT
bool ok = false;
PIByteArray ret = PICrypt::decrypt(data, _key, &ok);
if (!ok) return PIByteArray();
return ret;
#else
return PIByteArray();
#endif
}

View File

@@ -1,256 +1,215 @@
/*
PIP - Platform Independent Primitives
Simple packet wrap aroud any PIIODevice
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/>.
*/
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnonnull"
#endif
#include "pistreampacker.h"
#include "piiodevice.h"
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
/** \class PIStreamPacker
* @brief Simple packet wrap aroud any PIIODevice
*
* \section PIStreamPacker_synopsis Synopsis
* %PIStreamPacker provides simple pack/unpack logic for any data packets.
*
* When you call \a send() function data splited into several
* parts, \a packetSign() prepended to first part and \a sendRequest()
* event raised several times.
*
* When your device receive some data, call \a received() function.
* \a packetReceiveEvent() event will be raised when packet will be
* collected.
*
* Use \a assignDevice() to connect device to this %PIStreamPacker.
*
*/
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
crypt_frag = crypt_size = false;
aggressive_optimization = true;
packet_size = -1;
size_crypted_size = sizeof(int);
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::send(const PIByteArray & data) {
if (data.isEmpty()) return;
PIByteArray cd;
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();
PIByteArray hdr, part;
hdr << packet_sign;
if (crypt_size) {
PIByteArray crsz; crsz << int(cd.size_s());
hdr.append(cryptData(crsz));
} else
hdr << int(cd.size_s());
cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = true;
prog_s.bytes_all = data.size_s();
prog_s.bytes_current = 0;
prog_s.progress = 0.;
prog_s_mutex.unlock();
}
for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else part = PIByteArray(cd.data(pst), max_packet_size);
//piCout << "send" << part.size();
sendRequest(part);
pst += max_packet_size;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.bytes_current += part.size_s();
prog_s.progress = (double)prog_s.bytes_current / prog_s.bytes_all;
prog_s_mutex.unlock();
}
}
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = false;
prog_s_mutex.unlock();
}
}
void PIStreamPacker::received(uchar * readed, int size) {
received(PIByteArray(readed, size));
}
void PIStreamPacker::received(const PIByteArray & data) {
stream.append(data);
//piCout << "rec" << data.size();
while (!stream.isEmpty()) {
int hdr_size = sizeof(packet_sign) + size_crypted_size;
if (packet_size < 0) {
if (stream.size_s() < hdr_size) return;
ushort sign(0);
memcpy(&sign, stream.data(), 2);
if (sign != packet_sign) {
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
int sz = -1;
if (crypt_size) {
PIByteArray crsz((uint)size_crypted_size);
memcpy(crsz.data(), stream.data(2), size_crypted_size);
crsz = decryptData(crsz);
if (crsz.size() < sizeof(sz)) {
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
crsz >> sz;
} else {
memcpy(&sz, stream.data(2), size_crypted_size);
}
if (sz < 0) {
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
stream.remove(0, hdr_size);
packet.clear();
packet_size = sz;
if (packet_size == 0)
packet_size = -1;
else {
prog_r_mutex.lock();
prog_r.active = true;
prog_r.bytes_all = packet_size;
prog_r.bytes_current = 0;
prog_r.progress = 0.;
prog_r_mutex.unlock();
}
continue;
} else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps);
prog_r_mutex.lock();
prog_r.bytes_current = packet.size_s();
prog_r.progress = (double)prog_r.bytes_current / piMaxi(1, prog_r.bytes_all);
prog_r_mutex.unlock();
stream.remove(0, ps);
if (packet.size_s() == packet_size) {
PIByteArray cd;
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();
if (!cd.isEmpty()) {
packetReceived(cd);
packetReceiveEvent(cd);
}
packet.clear();
packet_size = -1;
prog_r_mutex.lock();
prog_r.active = false;
prog_r_mutex.unlock();
}
}
}
}
void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) return;
if (!dev->infoFlags()[PIIODevice::Reliable])
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
CONNECTU(dev, threadedReadEvent, this, received);
CONNECTU(this, sendRequest, dev, write);
}
PIStreamPacker::Progress PIStreamPacker::progressSend() const {
PIStreamPacker::Progress ret;
prog_s_mutex.lock();
ret = prog_s;
prog_s_mutex.unlock();
return ret;
}
PIStreamPacker::Progress PIStreamPacker::progressReceive() const {
PIStreamPacker::Progress ret;
prog_r_mutex.lock();
ret = prog_r;
prog_r_mutex.unlock();
return ret;
}
PIStreamPacker::Progress::Progress() {
active = false;
bytes_all = bytes_current = 0;
progress = 0.;
}
/*
PIP - Platform Independent Primitives
Simple packet wrap aroud any PIIODevice
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/>.
*/
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wnonnull"
#endif
#include "pistreampacker.h"
#include "piiodevice.h"
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
/** \class PIStreamPacker
* \brief Simple packet wrap aroud any PIIODevice
*
* \section PIStreamPacker_synopsis Synopsis
* %PIStreamPacker provides simple pack/unpack logic for any data packets.
*
* When you call \a send() function data splited into several
* parts, \a packetSign() prepended to first part and \a sendRequest()
* event raised several times.
*
* When your device receive some data, call \a received() function.
* \a packetReceiveEvent() event will be raised when packet will be
* collected.
*
* Use \a assignDevice() to connect device to this %PIStreamPacker.
*
*/
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
crypt_frag = crypt_size = false;
aggressive_optimization = true;
packet_size = -1;
size_crypted_size = sizeof(int);
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() {
packet.clear();
packet_size = -1;
stream.clear();
}
void PIStreamPacker::send(const PIByteArray & data) {
if (data.isEmpty()) return;
PIByteArray cd;
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();
PIByteArray hdr, part;
hdr << packet_sign;
if (crypt_size) {
PIByteArray crsz;
crsz << int(cd.size_s());
hdr.append(cryptData(crsz));
} else
hdr << int(cd.size_s());
cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1)
part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else
part = PIByteArray(cd.data(pst), max_packet_size);
// piCout << "send" << part.size();
sendRequest(part);
pst += max_packet_size;
}
}
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
received(PIByteArray(readed, size));
}
void PIStreamPacker::received(const PIByteArray & data) {
stream.append(data);
// piCout << "rec" << data.size();
while (!stream.isEmpty()) {
int hdr_size = sizeof(packet_sign) + size_crypted_size;
if (packet_size < 0) {
if (stream.size_s() < hdr_size) return;
ushort sign(0);
memcpy(&sign, stream.data(), 2);
if (sign != packet_sign) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
continue;
}
int sz = -1;
if (crypt_size) {
PIByteArray crsz((uint)size_crypted_size);
memcpy(crsz.data(), stream.data(2), size_crypted_size);
crsz = decryptData(crsz);
if (crsz.size() < sizeof(sz)) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
continue;
}
crsz >> sz;
} else {
memcpy(&sz, stream.data(2), size_crypted_size);
}
if (sz < 0) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
continue;
}
stream.remove(0, hdr_size);
packet.clear();
packet_size = sz;
if (packet_size == 0) packet_size = -1;
continue;
} else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps);
stream.remove(0, ps);
if (packet.size_s() == packet_size) {
PIByteArray cd;
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();
if (!cd.isEmpty()) {
packetReceived(cd);
packetReceiveEvent(cd);
}
packet.clear();
packet_size = -1;
}
}
}
}
void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) return;
if (!dev->infoFlags()[PIIODevice::Reliable]) {
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
}
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
CONNECT1(void, PIByteArray, this, sendRequest, dev, write);
}

View File

@@ -1,20 +1,20 @@
/*
PIP - Platform Independent Primitives
PILuaProgram
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PILuaProgram
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 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.
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/>.
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 "piluaprogram.h"
@@ -50,4 +50,3 @@ luabridge::LuaRef PILuaProgram::getGlobal(const PIString & name) {
luabridge::Namespace PILuaProgram::getGlobalNamespace() {
return luabridge::getGlobalNamespace(PRIVATE->lua_state);
}

View File

@@ -1,23 +1,26 @@
/*! @file picloudbase.h
* @brief PICloud Base - Base class for PICloudClient and PICloud Server
*/
/*! \file picloudbase.h
* \ingroup Cloud
* \~\brief
* \~english Base class for PICloudClient and PICloudServer
* \~russian Базовый класс для PICloudClient и PICloudServer
*/
/*
PIP - Platform Independent Primitives
PICloud Base - Base class for PICloudClient and PICloud Server
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PICloud Base - Base class for PICloudClient and PICloud Server
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 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.
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/>.
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 PICLOUDBASE_H
@@ -28,8 +31,7 @@
#include "pistreampacker.h"
class PIP_CLOUD_EXPORT PICloudBase
{
class PIP_CLOUD_EXPORT PICloudBase {
public:
PICloudBase();

View File

@@ -1,23 +1,26 @@
/*! @file picloudclient.h
* @brief PICloud Client
*/
/*! \file picloudclient.h
* \ingroup Cloud
* \~\brief
* \~english PICloud Client
* \~russian Клиент PICloud
*/
/*
PIP - Platform Independent Primitives
PICloud Client
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PICloud Client
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 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.
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/>.
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 PICLOUDCLIENT_H
@@ -27,37 +30,44 @@
#include "piconditionvar.h"
//! @brief PICloudClient
//! \brief PICloudClient
class PIP_CLOUD_EXPORT PICloudClient
: public PIIODevice
, public PICloudBase {
PIIODEVICE(PICloudClient, "");
class PIP_CLOUD_EXPORT PICloudClient: public PIIODevice, public PICloudBase
{
PIIODEVICE(PICloudClient)
public:
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudClient();
void setServerName(const PIString & server_name);
void setKeepConnection(bool on);
bool isConnected() const {return is_connected;}
bool isConnected() const { return is_connected; }
ssize_t bytesAvailable() const override { return buff.size(); }
void interrupt() override;
EVENT(connected)
EVENT(disconnected)
EVENT(connected);
EVENT(disconnected);
protected:
bool openDevice();
bool closeDevice();
int readDevice(void * read_to, int max_size);
int writeDevice(const void * data, int size);
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
bool openDevice() override;
bool closeDevice() override;
ssize_t readDevice(void * read_to, ssize_t max_size) override;
ssize_t writeDevice(const void * data, ssize_t size) override;
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
private:
EVENT_HANDLER1(void, _readed, PIByteArray &, data);
void internalDisconnect();
PIByteArray buff;
PIMutex mutex_buff;
PIMutex mutex_connect;
PIConditionVariable cond_buff;
PIConditionVariable cond_connect;
std::atomic_bool is_connected;
std::atomic_bool is_deleted;
};
#endif // PICLOUDCLIENT_H

View File

@@ -1,27 +1,58 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
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 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.
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/>.
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 Cloud Cloud
//! \~\brief
//! \~english Cloud transport over ethernet
//! \~russian Облачный транспорт через ethernet
//!
//! \~\details
//! \~english \section cmake_module_Cloud Building with CMake
//! \~russian \section cmake_module_Cloud Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::Cloud)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides server-side and client-side of PICloud transport.
//!
//! \~russian
//! Эти файлы обеспечивают серверную и клиентскую сторону транспорта PICloud.
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PICLOUDMODULE_H
#define PICLOUDMODULE_H
#include "picloudtcp.h"
#include "picloudclient.h"
#include "picloudserver.h"
#include "picloudtcp.h"
#endif // PICLOUDMODULE_H

View File

@@ -1,23 +1,26 @@
/*! @file picloudserver.h
* @brief PICloud Server
*/
/*! \file picloudserver.h
* \ingroup Cloud
* \~\brief
* \~english PICloud Server
* \~russian Сервер PICloud
*/
/*
PIP - Platform Independent Primitives
PICloud Server
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PICloud Server
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 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.
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/>.
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 PICLOUDSERVER_H
@@ -27,26 +30,32 @@
#include "piconditionvar.h"
class PIP_CLOUD_EXPORT PICloudServer: public PIIODevice, public PICloudBase
{
PIIODEVICE(PICloudServer)
class PIP_CLOUD_EXPORT PICloudServer
: public PIIODevice
, public PICloudBase {
PIIODEVICE(PICloudServer, "");
public:
//! PICloudServer
explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudServer();
class Client : public PIIODevice {
PIIODEVICE(PICloudServer::Client)
class Client: public PIIODevice {
PIIODEVICE(PICloudServer::Client, "");
friend class PICloudServer;
public:
Client(PICloudServer * srv = nullptr, uint id = 0);
virtual ~Client();
protected:
bool openDevice();
bool closeDevice();
int readDevice(void * read_to, int max_size);
int writeDevice(const void * data, int size);
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
bool openDevice() override;
bool closeDevice() override;
ssize_t readDevice(void * read_to, ssize_t max_size) override;
ssize_t writeDevice(const void * data, ssize_t size) override;
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
ssize_t bytesAvailable() const override { return buff.size(); }
void interrupt() override;
private:
void pushBuffer(const PIByteArray & ba);
@@ -62,13 +71,14 @@ public:
PIVector<PICloudServer::Client *> clients() const;
EVENT1(newConnection, PICloudServer::Client * , client)
EVENT1(newConnection, PICloudServer::Client *, client);
protected:
bool openDevice();
bool closeDevice();
int readDevice(void * read_to, int max_size);
int writeDevice(const void * data, int max_size);
bool openDevice() override;
bool closeDevice() override;
ssize_t readDevice(void * read_to, ssize_t max_size) override;
ssize_t writeDevice(const void * data, ssize_t max_size) override;
void interrupt() override;
private:
EVENT_HANDLER1(void, _readed, PIByteArray &, ba);
@@ -77,8 +87,13 @@ private:
int sendData(const PIByteArray & data, uint client_id);
PIVector<Client *> clients_;
PIVector<Client *> removed_clients_;
PIMap<uint, Client *> index_clients;
PITimer ping_timer;
PIConditionVariable cvar;
PIMutex open_mutex;
mutable PIMutex clients_mutex;
std::atomic_bool is_deleted;
};
#endif // PICLOUDSERVER_H

View File

@@ -1,28 +1,32 @@
/*! @file picloudtcp.h
* @brief PICloud TCP transport
*/
/*! \file picloudtcp.h
* \ingroup Cloud
* \~\brief
* \~english PICloud TCP transport
* \~russian TCP слой PICloud
*/
/*
PIP - Platform Independent Primitives
PICloud TCP transport
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
PICloud TCP transport
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 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.
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/>.
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 PICLOUDTCP_H
#define PICLOUDTCP_H
#include "pimutex.h"
#include "pip_cloud_export.h"
#include "pistring.h"
@@ -33,7 +37,6 @@ class PIStreamPacker;
namespace PICloud {
class PIP_CLOUD_EXPORT TCP {
public:
enum Version {
@@ -43,20 +46,21 @@ public:
enum Role {
InvalidRole = 0,
Server = 1,
Client = 2,
Server = 1,
Client = 2,
};
enum Type {
InvalidType = 0,
Connect = 1,
Disconnect = 2,
Data = 3,
Connect = 1,
Disconnect = 2,
Data = 3,
Ping = 4,
};
TCP(PIStreamPacker * s);
void setRole(Role r);
Role role() const {return (Role)header.role;}
Role role() const { return (Role)header.role; }
void setServerName(const PIString & server_name_);
PIString serverName() const;
@@ -65,8 +69,9 @@ public:
void sendDisconnected(uint client_id);
int sendData(const PIByteArray & data);
int sendData(const PIByteArray & data, uint client_id);
void sendPing();
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba);
PIByteArray parseData(PIByteArray & ba);
bool canParseData(PIByteArray & ba);
PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba);
PIByteArray parseConnect_d(PIByteArray & ba);
uint parseConnect(PIByteArray & ba);
@@ -76,16 +81,17 @@ private:
struct Header {
Header();
uchar version; // PICloud::Version
uchar type; // PICloud::Type
uchar role; // PICloud::Role
uchar type; // PICloud::Type
uchar role; // PICloud::Role
};
Header header;
PIByteArray suuid;
PIString server_name;
PIStreamPacker * streampacker;
PIMutex mutex_send;
};
}
} // namespace PICloud
#endif // PICLOUDTCP_H

View File

@@ -1,54 +1,85 @@
/*
PIP - Platform Independent Primitives
C++ code info structs
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
C++ code info structs
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 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.
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/>.
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 "picodeinfo.h"
#include "pivariant.h"
PIString PICodeInfo::EnumInfo::memberName(int value_) const {
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
if (e.value == value_)
return e.name;
piForeachC(PICodeInfo::EnumeratorInfo & e, members)
if (e.value == value_) return e.name.toString();
return PIString();
}
int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
if (e.name == name_)
return e.value;
piForeachC(PICodeInfo::EnumeratorInfo & e, members)
if (e.name.toString() == name_) return e.value;
return -1;
}
PIMap<PIString, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
PIMap<PIString, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
PIMap<PIString, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;
PIMap<PIString, PICodeInfo::AccessTypeFunction> * PICodeInfo::accessTypeFunctions;
bool __PICodeInfoInitializer__::_inited_ = false;
PIVariantTypes::Enum PICodeInfo::EnumInfo::toPIVariantEnum() {
PIVariantTypes::Enum en(name.toString());
for (auto m: members)
en << m.toPIVariantEnumerator();
if (!en.isEmpty()) en.selectValue(members.front().value);
return en;
}
PIVariant PICodeInfo::getMemberAsVariant(const void * p, const char * class_name, const char * member_name) {
if (!p || !class_name || !member_name || !accessTypeFunctions || !accessValueFunctions) return PIVariant();
AccessTypeFunction atf = accessTypeFunctions->value(PIStringAscii(class_name), (AccessTypeFunction)0);
AccessValueFunction avf = accessValueFunctions->value(PIStringAscii(class_name), (AccessValueFunction)0);
if (!p || !class_name || !member_name) return PIVariant();
AccessTypeFunction atf = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction) nullptr);
AccessValueFunction avf = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction) nullptr);
if (!atf || !avf) return PIVariant();
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

@@ -1,97 +1,214 @@
/*! @file picodeinfo.h
* @brief C++ code info structs
*/
/*! \file picodeinfo.h
* \ingroup Code
* \~\brief
* \~english C++ code info structs. See \ref code_model.
* \~russian Структуры для C++ кода. Подробнее \ref code_model.
*/
/*
PIP - Platform Independent Primitives
C++ code info structs
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
C++ code info structs
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 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.
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/>.
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 PICODEINFO_H
#define PICODEINFO_H
#include "piconstchars.h"
#include "pistringlist.h"
#include "pivarianttypes.h"
class PIVariant;
//! \~english Namespace contains structures for code generation. See \ref code_model.
//! \~russian Пространство имен содержит структуры для кодогенерации. Подробнее \ref code_model.
namespace PICodeInfo {
//! \~english
//! Type modifiers
//! \~russian
//! Модификаторы типа
enum TypeFlag {
NoFlag,
Const = 0x01,
Static = 0x02,
Mutable = 0x04,
Volatile = 0x08,
Inline = 0x10,
Virtual = 0x20,
Extern = 0x40
Const /** const */ = 0x01,
Static /** static */ = 0x02,
Mutable /** mutable */ = 0x04,
Volatile /** volatile */ = 0x08,
Inline /** inline */ = 0x10,
Virtual /** virtual */ = 0x20,
Extern /** extern */ = 0x40
};
typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
typedef PIMap<PIString, PIString> MetaMap;
typedef PIByteArray(*AccessValueFunction)(const void *, const char *);
typedef const char*(*AccessTypeFunction)(const char *);
typedef PIByteArray (*AccessValueFunction)(const void *, const char *);
typedef const char * (*AccessTypeFunction)(const char *);
//! \~english Type information
//! \~russian Информация о типе
struct PIP_EXPORT TypeInfo {
TypeInfo(const PIString & n = PIString(), const PIString & t = PIString(), PICodeInfo::TypeFlags f = 0, int b = -1) {name = n; type = t; flags = f; bits = b;}
bool isBitfield() const {return bits > 0;}
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
//! \~russian Возвращает битовым ли полем является переменная
bool isBitfield() const { return bits > 0; }
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta;
PIString name;
PIString type;
//! \~english Name
//! \~russian Имя
PIConstChars name;
//! \~english Type
//! \~russian Тип
PIConstChars type;
//! \~english Modifiers
//! \~russian Модификаторы
PICodeInfo::TypeFlags flags;
//! \~english Bitfield variable bit count
//! \~russian Количество бит битового поля
int bits;
};
//! \~english Method information
//! \~russian Информация о методе
struct PIP_EXPORT FunctionInfo {
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta;
PIString name;
//! \~english Name
//! \~russian Имя
PIConstChars name;
//! \~english Return type
//! \~russian Возвращаемые тип
TypeInfo return_type;
//! \~english Arguments types
//! \~russian Типы аргументов
PIVector<PICodeInfo::TypeInfo> arguments;
};
//! \~english Class or struct information
//! \~russian Информация о классе или структуре
struct PIP_EXPORT ClassInfo {
ClassInfo() {has_name = true;}
ClassInfo() { has_name = true; }
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta;
//! \~english Has name or not
//! \~russian Имеет или нет имя
bool has_name;
PIString type;
PIString name;
PIStringList parents;
//! \~english Type
//! \~russian Тип
PIConstChars type;
//! \~english Name
//! \~russian Имя
PIConstChars name;
//! \~english Parent names
//! \~russian Имена родителей
PIVector<PIConstChars> parents;
//! \~english Variables
//! \~russian Переменные
PIVector<PICodeInfo::TypeInfo> variables;
//! \~english Methods
//! \~russian Методы
PIVector<PICodeInfo::FunctionInfo> functions;
PIVector<PICodeInfo::ClassInfo * > children_info;
//! \~english Subclass list
//! \~russian Список наследников
PIVector<PICodeInfo::ClassInfo *> children_info;
};
//! \~english Enumerator information
//! \~russian Информация об элементе перечисления
struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIString & n = PIString(), 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()); }
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta;
PIString name;
//! \~english Name
//! \~russian Имя
PIConstChars name;
//! \~english Value
//! \~russian Значение
int value;
};
//! \~english Enum information
//! \~russian Информация о перечислении
struct PIP_EXPORT EnumInfo {
//! \~english Returns member name with value "value"
//! \~russian Возвращает имя элемента со значением "value"
PIString memberName(int value) const;
//! \~english Returns member value with name "name"
//! \~russian Возвращает значение элемента с именем "name"
int memberValue(const PIString & name) const;
//! \~english Returns as PIVariantTypes::Enum
//! \~russian Возвращает как PIVariantTypes::Enum
PIVariantTypes::Enum toPIVariantEnum();
//! \~english Custom PIMETA content
//! \~russian Произвольное содержимое PIMETA
MetaMap meta;
PIString name;
//! \~english Name
//! \~russian Имя
PIConstChars name;
//! \~english Members
//! \~russian Элементы
PIVector<PICodeInfo::EnumeratorInfo> members;
};
inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
inline PICout operator<<(PICout s, const PICodeInfo::TypeInfo & v) {
if (v.flags[Inline]) s << "inline ";
if (v.flags[Virtual]) s << "virtual ";
if (v.flags[Mutable]) s << "mutable ";
@@ -99,75 +216,160 @@ inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
if (v.flags[Static]) s << "static ";
if (v.flags[Const]) s << "const ";
s << v.type;
if (!v.name.isEmpty())
s << " " << v.name;
if (!v.name.isEmpty()) s << " " << v.name;
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) {
s.setControl(0, true);
inline PICout operator<<(PICout s, const PICodeInfo::ClassInfo & v) {
s.saveAndSetControls(0);
s << "class " << v.name;
if (!v.parents.isEmpty()) {
s << ": ";
bool first = true;
piForeachC (PIString & i, v.parents) {
if (first) first = false;
else s << ", ";
for (const auto & i: v.parents) {
if (first)
first = false;
else
s << ", ";
s << i;
}
}
s << " Meta" << v.meta << " {\n";
piForeachC (FunctionInfo & i, v.functions) {
for (const auto & i: v.functions) {
s << PICoutManipulators::Tab << i.return_type << " " << i.name << "(";
bool fa = true;
piForeachC (TypeInfo & a, i.arguments) {
if (fa) fa = false;
else s << ", ";
for (const auto & a: i.arguments) {
if (fa)
fa = false;
else
s << ", ";
s << a;
}
s << ") Meta" << i.meta << ";\n";
}
if (!v.functions.isEmpty() && !v.variables.isEmpty())
s << "\n";
piForeachC (TypeInfo & i, v.variables) {
if (!v.functions.isEmpty() && !v.variables.isEmpty()) s << "\n";
for (const auto & i: v.variables) {
s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n";
}
s << "}\n";
s.restoreControl();
s.restoreControls();
return s;
}
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
s.setControl(0, true);
inline PICout operator<<(PICout s, const PICodeInfo::EnumInfo & v) {
s.saveAndSetControls(0);
s << "enum " << v.name << " Meta" << v.meta << " {\n";
piForeachC (EnumeratorInfo & i, v.members) {
for (const auto & i: v.members) {
bool f = true;
if (f) f = false;
else s << ", ";
if (f)
f = false;
else
s << ", ";
s << PICoutManipulators::Tab << i << "\n";
}
s << "}\n";
s.restoreControl();
s.restoreControls();
return s;
}
extern PIP_EXPORT PIMap<PIString, PICodeInfo::ClassInfo * > * classesInfo;
extern PIP_EXPORT PIMap<PIString, PICodeInfo::EnumInfo * > * enumsInfo;
extern PIP_EXPORT PIMap<PIString, PICodeInfo::AccessValueFunction> * accessValueFunctions;
extern PIP_EXPORT PIMap<PIString, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
class PIP_EXPORT __Storage__ {
__Storage__();
~__Storage__();
public:
static __Storage__ * instance();
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
inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) {
if (!p || !class_name || !member_name || !accessValueFunctions) return PIByteArray();
AccessValueFunction af = accessValueFunctions->value(PIStringAscii(class_name), (AccessValueFunction)0);
if (!p || !class_name || !member_name) return PIByteArray();
AccessValueFunction af = PICODEINFO::accessValueFunctions().value(class_name, (AccessValueFunction)0);
if (!af) return PIByteArray();
return af(p, member_name);
}
inline const char * getMemberType(const char * class_name, const char * member_name) {
if (!class_name || !member_name || !accessTypeFunctions) return "";
AccessTypeFunction af = accessTypeFunctions->value(PIStringAscii(class_name), (AccessTypeFunction)0);
if (!class_name || !member_name) return "";
AccessTypeFunction af = PICODEINFO::accessTypeFunctions().value(class_name, (AccessTypeFunction)0);
if (!af) return "";
return af(member_name);
}
@@ -175,27 +377,15 @@ inline const char * getMemberType(const char * class_name, const char * member_n
PIP_EXPORT PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name);
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;}
template<typename T, typename std::enable_if<!std::is_assignable<T&, const T&>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) {}
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;
}
class PIP_EXPORT __PICodeInfoInitializer__ {
public:
__PICodeInfoInitializer__() {
if (_inited_) return;
_inited_ = true;
PICodeInfo::classesInfo = new PIMap<PIString, PICodeInfo::ClassInfo * >;
PICodeInfo::enumsInfo = new PIMap<PIString, PICodeInfo::EnumInfo * >;
PICodeInfo::accessValueFunctions = new PIMap<PIString, PICodeInfo::AccessValueFunction>;
PICodeInfo::accessTypeFunctions = new PIMap<PIString, PICodeInfo::AccessTypeFunction>;
}
static bool _inited_;
};
template<typename T, typename std::enable_if<!std::is_assignable<T &, const T &>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) {}
} // namespace PICodeInfo
static __PICodeInfoInitializer__ __picodeinfoinitializer__;
#endif // PICODEINFO_H

View File

@@ -1,21 +1,54 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Module includes
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 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.
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/>.
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 Code Code
//! \~\brief
//! \~english C++ code parsing
//! \~russian Разбор C++ кода
//!
//! \~\details
//! \~english \section cmake_module_Code Building with CMake
//! \~russian \section cmake_module_Code Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides parsing C++ code and storage to use results of \a pip_cmg utility.
//! See \ref code_model.
//!
//! \~russian
//! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg.
//! Подробнее \ref code_model.
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PICODEMODULE_H
#define PICODEMODULE_H

View File

@@ -1,26 +1,25 @@
/*
PIP - Platform Independent Primitives
C++ code parser
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
C++ code 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 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.
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/>.
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 "picodeparser.h"
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIStringList arg_vals;
while (!args_.isEmpty()) {
@@ -32,29 +31,32 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIString ca;
if (bi >= 0 && bi < ci) {
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('(', ')') + ')';
} else {
ca = args_.takeLeft(ci);
}
arg_vals << ca;
args_.trim(); args_.takeLeft(1); args_.trim();
args_.trim();
args_.takeLeft(1);
args_.trim();
}
if (args.size() != arg_vals.size()) {
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect")
<< args.size() << "arguments but takes" << arg_vals.size() << "!";
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect") << args.size() << "arguments but takes"
<< arg_vals.size() << "!";
if (ok != 0) *ok = false;
return PIString();
}
PIString ret = value;
for (int i = 0; i < args.size_s(); ++i) {
const PIString & an(args[i]), av(arg_vals[i]);
const PIString &an(args[i]), av(arg_vals[i]);
int ind(-1);
while ((ind = ret.find(an, ind + 1)) >= 0) {
PIChar ppc(0), pc(0), nc(0);
PIChar ppc, pc, nc;
if (ind > 1) ppc = ret[ind - 2];
if (ind > 0) pc = ret[ind - 1];
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(),1)[0];
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(), 1)[0];
if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars
ind--;
ret.replace(ind, an.size_s() + 1, '\"' + av + '\"');
@@ -72,9 +74,8 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
}
PICodeParser::PICodeParser() {
macros_iter = 32;
macros_iter = 32;
with_includes = true;
clear();
includes << "";
@@ -86,62 +87,66 @@ void PICodeParser::parseFile(const PIString & file, bool follow_includes) {
parseFileInternal(file, follow_includes);
/*piCout << "\n\n";
piForeachC (Entity * c, entities) {
piCout << "";
piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta;
if (c->parent_scope)
piCout << "parent" << c->parent_scope->name;
piCout << "Functions:";
piForeachC (Member & m, c->functions)
piCout << m.type << m.name << m.meta;
piCout << "Members:";
piForeachC (Member & m, c->members)
piCout << m.type << m.name << m.meta;
piCout << "";
piCout << c->type << c->name << c->parent_scope << c->parents << c->children << c->meta;
if (c->parent_scope)
piCout << "parent" << c->parent_scope->name;
piCout << "Functions:";
piForeachC (Member & m, c->functions)
piCout << m.type << m.name << m.meta;
piCout << "Members:";
piForeachC (Member & m, c->members)
piCout << m.type << m.name << m.meta;
}
piCout << "\n\nDefines:";
piForeachC (Define & m, defines)
piCout << PIStringAscii("define") << m.first << m.second;
piCout << PIStringAscii("define") << m.first << m.second;
piCout << "\n\nMacros:";
piForeachC (Macro & m, macros)
piCout << "Macro:" << m.name << m.args << m.value;
piCout << "Macro:" << m.name << m.args << m.value;
piCout << "\n\nClasses:";
piCout << "\n\nEnums:";
piForeachC (Enum & c, enums) {
piCout << PIStringAscii("enum") << c.name << c.meta;
piForeachC (EnumeratorInfo & e, c.members)
piCout << " " << e.name << '=' << e.value << e.meta;
piCout << PIStringAscii("enum") << c.name << c.meta;
piForeachC (EnumeratorInfo & e, c.members)
piCout << " " << e.name << '=' << e.value << e.meta;
}
piCout << "\n\nTypedefs:";
piForeachC (Typedef & c, typedefs)
piCout << PIStringAscii("typedef") << c;*/
piCout << PIStringAscii("typedef") << c;*/
}
void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) {
clear();
piForeachC (PIString & f, files)
piForeachC(PIString & f, files)
parseFileInternal(f, follow_includes);
/*piCout << "\n\nDefines:";
piForeachC (Define & m, defines)
piCout << PIStringAscii("define") << m.first << m.second;
piCout << PIStringAscii("define") << m.first << m.second;
piCout << "\n\nMacros:";
piForeachC (Macro & m, macros)
piCout << "Macro:" << m.name << m.args << m.value;
piCout << "Macro:" << m.name << m.args << m.value;
piCout << "\n\nClasses:";
piForeachC (Entity * c, entities)
piCout << PIStringAscii("class") << c->name << c->parents;
piCout << PIStringAscii("class") << c->name << c->parents;
piCout << "\n\nEnums:";
piForeachC (Enum & c, enums)
piCout << PIStringAscii("enum") << c.name << c.members;
piCout << PIStringAscii("enum") << c.name << c.members;
piCout << "\n\nTypedefs:";
piForeachC (Typedef & c, typedefs)
piCout << PIStringAscii("typedef") << c;*/
}
void PICodeParser::parseFileContent(PIString fc) {
parseFileContent(fc, false);
}
bool PICodeParser::isEnum(const PIString & name) {
piForeachC (Enum & e, enums)
if (e.name == name)
return true;
piForeachC(Enum & e, enums)
if (e.name == name) return true;
return false;
}
@@ -149,19 +154,19 @@ bool PICodeParser::isEnum(const PIString & name) {
bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes) {
if (proc_files[file]) return true;
with_includes = follow_includes;
cur_file = file;
cur_file = file;
PIFile f(file, PIIODevice::ReadOnly);
int ii = 0;
while (!f.isOpened() && ii < (includes.size_s() - 1)) {
f.setPath(includes[++ii] + '/' + file);
//piCout << "try" << f.path();
// piCout << "try" << f.path();
f.open(PIIODevice::ReadOnly);
}
if (!f.isOpened()) {
piCout << ("Error: can`t open file \"" + file + "\"!");
return false;
}
//piCout << "add" << file;
// piCout << "add" << file;
proc_files << f.path();
PIString fc = PIString::fromUTF8(f.readAll());
piCout << "parsing" << f.path() << "...";
@@ -174,7 +179,8 @@ bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes
void PICodeParser::clear() {
piForeach (Entity * i, entities) delete i;
piForeach(Entity * i, entities)
delete i;
defines.clear();
macros.clear();
enums.clear();
@@ -184,16 +190,150 @@ void PICodeParser::clear() {
cur_namespace.clear();
main_file.clear();
evaluator.clearCustomVariables();
cur_def_vis = Global;
anon_num = 0;
cur_def_vis = Global;
anon_num = 0;
PIStringList defs = PIStringAscii(PICODE_DEFINES).split(",");
piForeachC (PIString & d, defs)
piForeachC(PIString & d, defs)
defines << Define(d, "");
defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent")
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"),
"",
PIStringList() << "name"
<< "parent")
<< Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name")
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name") << Macro(PIStringAscii("PRIVATE_DECLARATION"))
<< Macro(PIStringAscii("EVENT"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT1"),
"void name(a0 n0);",
PIStringList() << "name"
<< "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT2"),
"void name(a0 n0, a1 n1);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT3"),
"void name(a0 n0, a1 n1, a2 n2);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT4"),
"void name(a0 n0, a1 n1, a2 n2, a3 n3);",
PIStringList() << "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3")
<< Macro(PIStringAscii("EVENT_HANDLER"),
"ret name()",
PIStringList() << "ret"
<< "name")
<< Macro(PIStringAscii("EVENT_HANDLER0"),
"ret name()",
PIStringList() << "ret"
<< "name")
<< Macro(PIStringAscii("EVENT_HANDLER1"),
"ret name(a0 n0)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT_HANDLER2"),
"ret name(a0 n0, a1 n1)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT_HANDLER3"),
"ret name(a0 n0, a1 n1, a2 n2)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT_HANDLER4"),
"ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3")
<< Macro(PIStringAscii("EVENT_VHANDLER"),
"virtual ret name()",
PIStringList() << "ret"
<< "name")
<< Macro(PIStringAscii("EVENT_VHANDLER0"),
"virtual ret name()",
PIStringList() << "ret"
<< "name")
<< Macro(PIStringAscii("EVENT_VHANDLER1"),
"virtual ret name(a0 n0)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0")
<< Macro(PIStringAscii("EVENT_VHANDLER2"),
"virtual ret name(a0 n0, a1 n1)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1")
<< Macro(PIStringAscii("EVENT_VHANDLER3"),
"virtual ret name(a0 n0, a1 n1, a2 n2)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2")
<< Macro(PIStringAscii("EVENT_VHANDLER4"),
"virtual ret name(a0 n0, a1 n1, a2 n2, a3 n3)",
PIStringList() << "ret"
<< "name"
<< "a0"
<< "n0"
<< "a1"
<< "n1"
<< "a2"
<< "n2"
<< "a3"
<< "n3");
}
bool PICodeParser::parseFileContent(PIString & fc, bool main) {
static const PIString s_ns = PIStringAscii("::");
static const PIString s_bo = PIStringAscii("{\n");
static const PIString s_bc = PIStringAscii("\n}\n");
static const PIString s_class = PIStringAscii("class");
@@ -209,7 +349,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
char c = 0, pc = 0;
PIString pfc, line, ccmn, tmp;
PIMap<PIString, PIString> cchars;
/// Remove comments, join multiline '*' and replace '*' to $n (cchars)
fc.replaceAll("\r\n", '\n');
fc.replaceAll('\r', '\n');
@@ -218,7 +358,8 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (i > 0) pc = c;
c = fc[i].toAscii();
if (c == '"' && !mlc && pc != '\'') {
if (i > 0) if (fc[i - 1] == '\\') continue;
if (i > 0)
if (fc[i - 1] == '\\') continue;
cc = !cc;
continue;
}
@@ -229,46 +370,62 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
continue;
}
if (cc) continue;
if (fc.mid(i, 2) == "/*") {mlc = true; 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;}
if (fc.mid(i, 2) == "/*") {
mlc = true;
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);
if (main) return true;
bool replaced = true;
bool replaced = true;
int replaced_cnt = 0;
while (replaced) {
//piCout << "MACRO iter" << replaced_cnt;
// piCout << "MACRO iter" << replaced_cnt;
if (replaced_cnt >= macros_iter) {
piCout << "Error: recursive macros detected!";
break;//return false;
break; // return false;
}
replaced_cnt++;
replaced = false;
piForeachC (Define & d, defines) {
piForeachC(Define & d, defines) {
int ind(-1);
while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
PIChar pc(0), nc(0);
PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1];
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(),1)[0];
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(), 1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
pfc.replace(ind, d.first.size_s(), d.second);
ind -= d.first.size_s() - d.second.size_s();
replaced = true;
}
}
piForeachC (Macro & m, macros) {
piForeachC(Macro & m, macros) {
int ind(-1);
while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
PIChar pc(0), nc(0);
PIChar pc, nc;
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;
PIString ret, range; bool ok(false);
PIString ret, range;
bool ok(false);
range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')');
ret = m.expand(range, &ok);
ret = m.expand(range, &ok);
if (!ok) return false;
int rlen = pfc.find(range, ind + m.name.size_s()) + range.size_s() + 1 - ind;
pfc.replace(ind, rlen, ret);
@@ -279,16 +436,23 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
}
replaceMeta(pfc);
//piCout << NewLine << "file" << cur_file << pfc;
int pl = -1;
// piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
int pl = -1;
cur_def_vis = Global;
while (!pfc.isEmpty()) {
pfc.trim();
int nl = pfc.size_s();
if (pl == nl) break;
pl = nl;
if (pfc.left(9) == s_namespace) {
pfc.cutLeft(pfc.find('{') + 1);
pfc.cutLeft(9);
PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += pfc.takeCWord() + s_ns;
ccmn = pfc.takeRange('{', '}');
// piCout << "namespace" << cur_namespace;
parseClass(0, ccmn, true);
cur_namespace = prev_namespace;
continue;
}
if (pfc.left(8) == s_template) {
@@ -296,17 +460,28 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
pfc.takeRange('<', '>');
bool def = !isDeclaration(pfc, 0, &end);
pfc.cutLeft(end);
if (def) pfc.takeRange('{', '}');
else pfc.takeSymbol();
if (def)
pfc.takeRange('{', '}');
else
pfc.takeSymbol();
continue;
}
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);
if (dind < 0 && find < 0) {pfc.cutLeft(6); continue;}
if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;}
// piCout << pfc.left(6) << dind << find;
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;
pfc.remove(0, ccmn.size());
parseClass(0, ccmn);
parseClass(0, ccmn, false);
continue;
}
if (pfc.left(4) == s_enum) {
@@ -314,6 +489,12 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
tmp = pfc.takeCWord();
pfc.trim();
MetaMap meta = maybeMeta(pfc);
if (tmp == s_class || tmp == s_struct) {
tmp = pfc.takeCWord();
pfc.trim();
MetaMap smeta = maybeMeta(pfc);
meta << smeta;
}
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
pfc.takeSymbol();
continue;
@@ -321,8 +502,10 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (pfc.left(7) == s_typedef) {
pfc.cutLeft(7);
typedefs << parseTypedef(pfc.takeLeft(pfc.find(';')));
if (typedefs.back().first.isEmpty()) typedefs.pop_back();
else root_.typedefs << typedefs.back();
if (typedefs.back().first.isEmpty())
typedefs.pop_back();
else
root_.typedefs << typedefs.back();
pfc.takeSymbol();
continue;
}
@@ -340,7 +523,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
}
parseMember(&root_, str);
}
return true;
}
@@ -349,49 +532,55 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
static const PIString s_ss = PIStringAscii(" ");
static const PIString s_M = PIStringAscii("$M");
static const PIString s_class = PIStringAscii("class");
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
PIString cd = fc.trimmed().removeAll('\n').replaceAll('\t', ' ').replaceAll(s_ss, ' '), pn;
MetaMap meta;
int ind = cd.find(s_M);
if (ind >= 0) {
meta = tmp_meta.value(cd.takeMid(ind, 5));
cd.replaceAll(s_ss, ' ');
}
//piCout << "found class <****\n" << cd << "\n****>";
// piCout << "found class <****\n" << cd << "\n****>";
ind = cd.find(':');
PIVector<Entity * > parents;
PIVector<Entity *> parents;
if (ind > 0) {
PIStringList pl = cd.takeMid(ind + 1).trim().split(',');
cd.cutRight(1);
Entity * pe = 0;
piForeachC (PIString & p, pl) {
if (p.contains(' ')) pn = p.mid(p.find(' ') + 1);
else pn = p;
piForeachC(PIString & p, pl) {
if (p.contains(' '))
pn = p.mid(p.find(' ') + 1);
else
pn = p;
pe = findEntityByName(pn);
if (pe == 0) ;//{piCout << "Error: can`t find" << pn;}
else parents << pe;
if (pe == 0)
; //{piCout << "Error: can`t find" << pn;}
else
parents << pe;
}
}
PIString typename_ = cd.left(6).trim();
bool is_class = typename_ == s_class;
cur_def_vis = (is_class ? Private : Public);
PIString cn = cd.mid(6).trim();
bool has_name = !cn.isEmpty();
bool is_class = typename_ == s_class;
Visibility vis = cur_def_vis;
cur_def_vis = (is_class ? Private : Public);
PIString cn = cd.mid(6).trim();
bool has_name = !cn.isEmpty();
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
//piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return 0;
Entity * e = new Entity();
e->meta = meta;
e->name = cur_namespace + cn;
e->type = typename_;
e->has_name = has_name;
e->parents = parents;
e->file = cur_file;
// piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return nullptr;
Entity * e = new Entity();
e->meta = meta;
e->name = cur_namespace + cn;
e->type = typename_;
e->has_name = has_name;
e->parents = parents;
e->visibility = vis;
e->file = cur_file;
entities << e;
return e;
}
PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace) {
static const PIString s_ns = PIStringAscii("::");
static const PIString s_public = PIStringAscii("public");
static const PIString s_protected = PIStringAscii("protected");
@@ -402,58 +591,93 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
static const PIString s_enum = PIStringAscii("enum");
static const PIString s_friend = PIStringAscii("friend");
static const PIString s_typedef = PIStringAscii("typedef");
static const PIString s_namespace = PIStringAscii("namespace");
static const PIString s_template = PIStringAscii("template");
Visibility prev_vis = cur_def_vis;
Visibility prev_vis = cur_def_vis;
int dind = fc.find('{'), find = fc.find(';'), end = 0;
if (dind < 0 && find < 0) return PIString();
if (dind < 0 || find < dind) return fc.left(find);
//piCout << "parse class <****\n" << fc.left(20) << "\n****>";
Entity * ce = parseClassDeclaration(fc.takeLeft(dind));
fc.trim().cutLeft(1).cutRight(1).trim();
//piCout << "found class <****\n" << fc << "\n****>";
if (!ce) return PIString();
if (parent) parent->children << ce;
ce->parent_scope = parent;
int ps = -1;
bool def = false;
if (dind < 0 && find < 0) return;
// piCout << "parse class <****\n" << fc << "\n****>";
Entity * ce = parent;
if (!is_namespace) {
ce = parseClassDeclaration(fc.takeLeft(dind));
fc.trim().cutLeft(1).cutRight(1).trim();
}
// piCout << "found class <****\n" << fc << "\n****>";
if (ce) {
if (parent) parent->children << ce;
ce->parent_scope = parent;
}
int ps = -1;
bool def = false;
PIString prev_namespace = cur_namespace, stmp;
cur_namespace = ce->name + s_ns;
//piCout << "parse class" << ce->name << "namespace" << cur_namespace;
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
if (ce) cur_namespace += ce->name + s_ns;
// piCout << "parse class" << ce->name << "namespace" << cur_namespace;
// piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) {
PIString cw = fc.takeCWord(), tmp;
//piCout << "\ntaked word" << cw;
if (cw == s_public ) {cur_def_vis = Public; 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;}
// piCout << "\ntaked word" << cw;
if (cw == s_public) {
cur_def_vis = Public;
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) {
PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += fc.takeCWord() + s_ns;
ccmn = fc.takeRange('{', '}');
parseClass(ce, ccmn, true);
cur_namespace = prev_namespace;
continue;
}
if (cw == s_class || cw == s_struct || cw == s_union) {
// piCout << cw << isDeclaration(fc, 0, &end);
if (isDeclaration(fc, 0, &end)) {
fc.cutLeft(end);
fc.takeSymbol();
continue;
}
tmp = fc.takeLeft(fc.find('{'));
tmp = fc.takeLeft(fc.find('{'));
stmp = fc.takeRange('{', '}');
fc.takeSymbol();
stmp = cw + ' ' + tmp + '{' + stmp + '}';
parseClass(ce, stmp);
stmp = cw + ' ' + tmp + '{' + stmp + '}';
parseClass(ce, stmp, false);
continue;
}
if (cw == s_enum) {
tmp = fc.takeCWord();
fc.trim();
MetaMap meta = maybeMeta(fc);
if (tmp == s_class || tmp == s_struct) {
tmp = fc.takeCWord();
fc.trim();
MetaMap smeta = maybeMeta(fc);
meta << smeta;
}
parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
fc.takeSymbol();
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) {
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
typedefs << ce->typedefs.back();
typedefs.back().first.insert(0, cur_namespace);
if (ce->typedefs.back().first.isEmpty())
ce->typedefs.pop_back();
if (ce) {
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
typedefs << ce->typedefs.back();
typedefs.back().first.insert(0, cur_namespace);
if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back();
}
fc.takeSymbol();
continue;
}
@@ -461,22 +685,26 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
fc.takeRange('<', '>');
def = !isDeclaration(fc, 0, &end);
fc.cutLeft(end);
if (def) fc.takeRange('{', '}');
else fc.takeSymbol();
if (def)
fc.takeRange('{', '}');
else
fc.takeSymbol();
continue;
}
def = !isDeclaration(fc, 0, &end);
tmp = (cw + fc.takeLeft(end)).trim();
if (!tmp.isEmpty())
parseMember(ce, tmp);
if (def) fc.takeRange('{', '}');
else fc.takeSymbol();
if (ps == fc.size_s()) {fc.cutLeft(1);}
if (!tmp.isEmpty() && ce) parseMember(ce, tmp);
if (def)
fc.takeRange('{', '}');
else
fc.takeSymbol();
if (ps == fc.size_s()) {
fc.cutLeft(1);
}
ps = fc.size_s();
}
cur_def_vis = prev_vis;
cur_def_vis = prev_vis;
cur_namespace = prev_namespace;
return ce->name;
}
@@ -484,7 +712,7 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
PICodeParser::MetaMap ret;
if (fc.isEmpty()) return ret;
PIStringList ml = fc.split(',');
piForeachC (PIString & m, ml) {
piForeachC(PIString & m, ml) {
int i = m.find('=');
if (i < 0) {
ret[m.trimmed()] = PIString();
@@ -495,55 +723,61 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
ret[m.left(i).trim()] = mv;
}
}
//piCout << ms << ret;
// piCout << ms << ret;
return ret;
}
bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta) {
static const PIString s_ss = PIStringAscii(" ");
static const PIString s_M = PIStringAscii("$M");
//piCout << PIStringAscii("enum") << name << fc;
static const PIString s_M = PIStringAscii("$M");
// piCout << PIStringAscii("enum") << name << fc;
Enum e(name);
e.meta = meta;
PIStringList vl(fc.split(','));
PIString vn;
int cv = -1, ind = 0;
piForeach (PIString & v, vl) {
piForeach(PIString & v, vl) {
MetaMap meta;
int mi = v.find(s_M);
if (mi >= 0) {
meta = tmp_meta.value(v.takeMid(mi, 5));
v.replaceAll(s_ss, ' ');
}
vn = v; ind = v.find('=');
if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);}
vn = v;
ind = v.find('=');
if (ind > 0) {
cv = v.right(v.size_s() - ind - 1).toInt();
vn = v.left(ind);
}
if (ind < 0) ++cv;
e.members << EnumeratorInfo(vn.trim(), cv, meta);
}
if (!e.members.isEmpty())
if (e.members.back().name.isEmpty())
e.members.pop_back();
if (e.members.back().name.isEmpty()) e.members.pop_back();
enums << e;
return true;
}
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
//piCout << "parse typedef" << fc;
// piCout << "parse typedef" << fc;
Typedef td;
fc.replaceAll('\t', ' ');
if (fc.contains('(')) {
int start = fc.find('('), end = fc.find(')');
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();
} else {
td.first = fc.takeMid(fc.findLast(' ')).trim();
td.first = fc.takeMid(fc.findLast(' ')).trim();
td.second = fc.trim();
}
//piCout << "found typedef" << td;
// piCout << "found typedef" << td;
return td;
}
@@ -579,22 +813,26 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
if (fc.trim().isEmpty()) return true;
if (fc.find(s_operator) >= 0) return true;
tmp_temp.clear();
//piCout << "parse member" << fc;
// piCout << "parse member" << fc;
int ts = fc.find('<'), te = 0;
PIString ctemp, crepl;
while (ts >= 0) {
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');
fc.replace(ts, ctemp.size_s() + 2, crepl);
tmp_temp[crepl] = '<' + ctemp + '>';
ts = fc.find('<', te);
ts = fc.find('<', te);
}
fc.replaceAll('\n', ' ').replaceAll('\t', ' ').replaceAll(s_ss, ' ').replaceAll(s_cs, ',').replaceAll(s_sb, '(').replaceAll(s_sM, s_M);
//piCout << "parse member" << fc;
// piCout << "parse member" << fc;
PIStringList tl, al;
Member me;
//piCout << fc;
// piCout << fc;
if (fc.contains('(')) {
MetaMap meta;
int ind = fc.find(s_M);
@@ -604,16 +842,16 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
}
fc.cutRight(fc.size_s() - fc.findLast(')') - 1);
te = fc.find('(');
//piCout << fc;
// piCout << fc;
for (ts = te - 1; ts >= 0; --ts)
if (!_isCChar(fc[ts]) && !(fc[ts].isDigit())) break;
//piCout << "takeMid" << ts + 1 << te - ts - 1;
// piCout << "takeMid" << ts + 1 << te - ts - 1;
me.meta = meta;
me.name = fc.takeMid(ts + 1, te - ts - 1);
if (me.name == parent->name) return true;
me.arguments_full = fc.takeMid(ts + 2).cutRight(1).split(',');
me.type = fc.cutRight(1).trim();
me.visibility = cur_def_vis;
me.type = fc.cutRight(1).trim();
me.visibility = cur_def_vis;
if (me.type.find(s_inline_s) >= 0) {
me.attributes |= Inline;
me.type.removeAll(s_inline_s);
@@ -628,20 +866,18 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
}
normalizeEntityNamespace(me.type);
int i = 0;
//piCout << me.arguments_full;
piForeach (PIString & a, me.arguments_full)
if ((i = a.find('=')) > 0)
a.cutRight(a.size_s() - i).trim();
// piCout << me.arguments_full;
piForeach(PIString & a, me.arguments_full)
if ((i = a.find('=')) > 0) a.cutRight(a.size_s() - i).trim();
for (int j = 0; j < me.arguments_full.size_s(); ++j)
if (me.arguments_full[j] == s_void) {
me.arguments_full.remove(j);
--j;
}
me.arguments_type = me.arguments_full;
piForeach (PIString & a, me.arguments_type) {
piForeach(PIString & a, me.arguments_type) {
crepl.clear();
if (a.contains('['))
crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
if (a.contains('[')) crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
for (ts = a.size_s() - 1; ts >= 0; --ts)
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
a.cutRight(a.size_s() - ts - 1);
@@ -650,31 +886,34 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
a.trim();
}
restoreTmpTemp(&me);
//piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
// piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
parent->functions << me;
} else {
if (fc.endsWith(';')) fc.cutRight(1);
//piCout << "member" << fc;
// piCout << "member" << fc;
if (fc.startsWith(s_using) || !(fc.contains(' ') || fc.contains('\t') || fc.contains('\n'))) return true;
int bits = extractMemberBits(fc);
tl = fc.split(',');
//piCout << "member" << fc << tl;
//piCout << "member after eb" << fc << ", bits =" << bits;
tl = fc.split(',');
// piCout << "member" << fc << tl;
// piCout << "member after eb" << fc << ", bits =" << bits;
if (tl.isEmpty()) return true;
piForeach (PIString & v, tl)
piForeach(PIString & v, tl)
removeAssignment(v);
bool vn = true;
ctemp = tl.front().trim();
ctemp = tl.front().trim();
PIString meta_t;
if (ctemp.contains(s_M)) {
meta_t = ctemp.takeMid(ctemp.find(s_M), 5);
ctemp.trim();
}
for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
if (vn) {
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;
ctemp += meta_t;
restoreTmpTemp(&me);
@@ -702,21 +941,21 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
type.trim();
normalizeEntityNamespace(type);
tl[0] = ctemp.trim();
//piCout << "vars" << tl;
piForeachC (PIString & v, tl) {
// piCout << "vars" << tl;
piForeachC(PIString & v, tl) {
crepl.clear();
me.name = v.trimmed();
me.type = type;
restoreTmpMeta(&me);
if (me.name.isEmpty()) continue;
if (me.name.contains('['))
crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
if (me.name.contains('[')) crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
while (!me.name.isEmpty()) {
if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) {
me.type += me.name.takeLeft(1);
me.name.trim();
} else break;
} else
break;
}
me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*'));
me.type += crepl;
@@ -726,12 +965,12 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
if (cdim.isEmpty()) break;
me.dims << cdim;
}
//PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
//piCout << "var" << v << me.type << me.name << me.bits;
// PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
// piCout << "var" << v << me.type << me.name << me.bits;
parent->members << me;
}
}
//piCout << "parse member" << fc;
// piCout << "parse member" << fc;
return true;
}
@@ -763,13 +1002,25 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
break;
}
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_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;}
if (n.find(s_s_const_s) >= 0) {
n.replaceAll(s_s_const_s, "");
pref += s_const_s;
}
if (n.find(s_s_static_s) >= 0) {
n.replaceAll(s_s_static_s, "");
pref += s_static_s;
}
if (n.find(s_s_mutable_s) >= 0) {
n.replaceAll(s_s_mutable_s, "");
pref += s_mutable_s;
}
if (n.find(s_s_volatile_s) >= 0) {
n.replaceAll(s_s_volatile_s, "");
pref += s_volatile_s;
}
n.trim();
int f = 0;
piForeachC (Entity * e, entities) {
piForeachC(Entity * e, entities) {
if (e->name == n) {
n = (pref + n + suff).trim();
return;
@@ -781,20 +1032,20 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
return;
}
}
piForeachC (Enum & e, enums) {
piForeachC(Enum & e, enums) {
if ((f = e.name.find(n)) >= 0)
if (e.name.at(f - 1) == PIChar(':'))
if (e.name.find(cur_namespace) >= 0) {
//piCout << "change" << n << "to" << e.name + suff;
// piCout << "change" << n << "to" << e.name + suff;
n = pref + e.name + suff;
return;
}
}
piForeachC (Typedef & e, typedefs) {
piForeachC(Typedef & e, typedefs) {
if ((f = e.first.find(n)) >= 0)
if (e.first.at(f - 1) == PIChar(':'))
if (e.first.find(cur_namespace) >= 0) {
//piCout << "change" << n << "to" << e.name + suff;
// piCout << "change" << n << "to" << e.name + suff;
n = pref + e.first + suff;
return;
}
@@ -805,12 +1056,12 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
void PICodeParser::restoreTmpTemp(Member * e) {
static const PIString s_T = PIStringAscii("$T");
int i = 0;
piForeach (PIString & a, e->arguments_full) {
int i = 0;
piForeach(PIString & a, e->arguments_full) {
while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
}
piForeach (PIString & a, e->arguments_type) {
piForeach(PIString & a, e->arguments_type) {
while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
}
@@ -821,7 +1072,7 @@ void PICodeParser::restoreTmpTemp(Member * e) {
void PICodeParser::restoreTmpMeta(PICodeParser::Member * e) {
static const PIString s_M = PIStringAscii("$M");
int i = e->name.find(s_M);
int i = e->name.find(s_M);
if (i < 0) return;
e->meta = tmp_meta[e->name.takeMid(i, 5)];
}
@@ -843,7 +1094,7 @@ bool PICodeParser::macroCondition(const PIString & mif, PIString mifcond) {
static const PIString s_ifndef = PIStringAscii("ifndef");
static const PIString s_if = PIStringAscii("if");
static const PIString s_elif = PIStringAscii("elif");
//piCout << "macroCondition" << mif << mifcond;
// piCout << "macroCondition" << mif << mifcond;
if (mif == s_ifdef) return isDefineExists(mifcond);
if (mif == s_ifndef) return !isDefineExists(mifcond);
if (mif == s_if || mif == s_elif) {
@@ -862,52 +1113,65 @@ double PICodeParser::procMacrosCond(PIString fc) {
char cc, nc;
PIString ce;
fc.removeAll(s_defined);
//piCout << "procMacrosCond" << fc;
// piCout << "procMacrosCond" << fc;
while (!fc.isEmpty()) {
cc = fc[0].toAscii();
nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
if (cc == '!') {neg = true; fc.pop_front(); 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 (cc == '!') {
neg = true;
fc.pop_front();
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) {
ce = fc.takeCWord();
if (ce.isEmpty()) ce = fc.takeNumber();
}
if (first) {
first = false;
ret = br ? brv : defineValue(ce);
ret = br ? brv : defineValue(ce);
if (neg) ret = -ret;
} else {
//piCout << "oper" << oper << "with" << ce;
// piCout << "oper" << oper << "with" << ce;
if (!br) brv = defineValue(ce);
switch (oper) {
case 1: ret = ret && (neg ? -brv : brv); break;
case 2: ret = ret || (neg ? -brv : brv); break;
case 1: ret = ret && (neg ? -brv : brv); break;
case 2: ret = ret || (neg ? -brv : brv); break;
}
}
if (ps == fc.size_s()) fc.cutLeft(1);
ps = fc.size_s();
br = neg = false;
}
//piCout << "return" << ret;
// piCout << "return" << ret;
return ret;
}
bool PICodeParser::isDefineExists(const PIString & dn) {
piForeachC (Define & d, defines) {
if (d.first == dn)
return true;
piForeachC(Define & d, defines) {
if (d.first == dn) return true;
}
return false;
}
double PICodeParser::defineValue(const PIString & dn) {
piForeachC (Define & d, defines) {
if (d.first == dn)
return d.second.isEmpty() ? 1. : d.second.toDouble();
piForeachC(Define & d, defines) {
if (d.first == dn) return d.second.isEmpty() ? 1. : d.second.toDouble();
}
return dn.toDouble();
}
@@ -924,28 +1188,33 @@ void PICodeParser::replaceMeta(PIString & dn) {
ms = dn.findRange('(', ')', '\\', s + 6, &ml);
if (ms < 0) return;
PIString meta = dn.mid(ms, ml).trim();
PIString rm = s_M + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, '0');
PIString rm = s_M + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, '0');
dn.replace(s, ms + ml + 1 - s, rm);
//piCout << "FOUND META \"" << meta << '\"';
// piCout << "FOUND META \"" << meta << '\"';
tmp_meta[rm] = parseMeta(meta);
s = dn.find(s_PIMETA);
s = dn.find(s_PIMETA);
}
}
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
piForeach (Entity * e, entities)
if (e->name == en)
return e;
piForeach(Entity * e, entities)
if (e->name == en) return e;
return 0;
}
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
int dind = fc.find('{', start), find = fc.find(';', start);
//piCout << "isDeclaration" << dind << find << fc.left(10);
if (dind < 0 && find < 0) {if (end) *end = -1; return true;}
if (dind < 0 || find < dind) {if (end) *end = find; return true;}
// piCout << "isDeclaration" << dind << find << fc.left(10);
if (dind < 0 && find < 0) {
if (end) *end = -1;
return true;
}
if (dind < 0 || find < dind) {
if (end) *end = find;
return true;
}
if (end) *end = dind;
return false;
}
@@ -958,7 +1227,7 @@ bool PICodeParser::isMainFile(const PIString & fc) {
if (csi < 0) csi = fc.find(PIStringAscii("\tmain"), si);
if (csi < 0) csi = fc.find(PIStringAscii("\nmain"), si);
if (csi < 0) return false;
si = csi;
si = csi;
int fi = fc.find('(', si + 5);
if (fi < 0) return false;
if (fi - si < 10) {
@@ -983,68 +1252,80 @@ PIString PICodeParser::procMacros(PIString fc) {
int ifcnt = 0;
bool grab = false, skip = false, cond_ok = false;
PIString pfc, nfc, line, mif, mifcond;
//piCout << "procMacros\n<******" << fc << "\n******>";
// piCout << "procMacros\n<******" << fc << "\n******>";
fc += '\n';
while (!fc.isEmpty()) {
line = fc.takeLine().trimmed();
if (line.left(1) == PIChar('#')) {
mifcond = line.mid(1);
mif = mifcond.takeCWord();
//piCout << mif;
//piCout << "mif mifcond" << mif << mifcond << ifcnt;
mif = mifcond.takeCWord();
// piCout << mif;
// piCout << "mif mifcond" << mif << mifcond << ifcnt;
if (skip || grab) {
if (mif.left(2) == s_if) ifcnt++;
if (mif.left(5) == s_endif) {
if (ifcnt > 0) ifcnt--;
if (ifcnt > 0)
ifcnt--;
else {
//piCout << "main endif" << skip << grab;
if (grab) pfc << procMacros(nfc);
// piCout << "main endif" << skip << grab;
if (grab) pfc += procMacros(nfc);
skip = grab = false;
continue;
}
}
if (mif.left(4) == s_elif && ifcnt == 0) {
//piCout << "main elif" << skip << grab << cond_ok;
// piCout << "main elif" << skip << grab << cond_ok;
if (cond_ok) {
if (grab) {
pfc << procMacros(nfc);
skip = true; grab = false;
pfc += procMacros(nfc);
skip = true;
grab = false;
}
continue;
}
if (skip) {
//piCout << "check elif" << skip << grab << cond_ok;
// piCout << "check elif" << skip << grab << cond_ok;
if (!macroCondition(mif, mifcond.trimmed())) continue;
//piCout << "check elif ok";
skip = false; grab = cond_ok = true;
// piCout << "check elif ok";
skip = false;
grab = cond_ok = true;
continue;
}
continue;
}
if (mif.left(4) == s_else && ifcnt == 0) {
//piCout << "main else" << skip << grab;
if (grab) pfc << procMacros(nfc);
if (skip && !cond_ok) {skip = false; grab = true;}
else {skip = true; grab = false;}
// piCout << "main else" << skip << grab;
if (grab) pfc += procMacros(nfc);
if (skip && !cond_ok) {
skip = false;
grab = true;
} else {
skip = true;
grab = false;
}
continue;
}
if (grab) nfc << line << '\n';
if (grab) nfc += line + '\n';
continue;
}
if (mif.left(2) == s_if) {
//piCout << "main if";
// piCout << "main if";
skip = grab = cond_ok = false;
if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true;
else skip = true;
if (macroCondition(mif, mifcond.trimmed()))
grab = cond_ok = true;
else
skip = true;
ifcnt = 0;
nfc.clear();
} else {
parseDirective(line.cutLeft(1).trim());
//return false; /// WARNING: now skip errors
// return false; /// WARNING: now skip errors
}
} else {
if (grab) nfc << line << '\n';
else if (!skip) pfc << line << '\n';
if (grab)
nfc += line + '\n';
else if (!skip)
pfc += line + '\n';
}
}
return pfc;
@@ -1058,7 +1339,7 @@ bool PICodeParser::parseDirective(PIString d) {
static const PIString s_PIMETA = PIStringAscii("PIMETA");
if (d.isEmpty()) return true;
PIString dname = d.takeCWord();
//piCout << "parseDirective" << d;
// piCout << "parseDirective" << d;
if (dname == s_include) {
d.replaceAll('<', '\"').replaceAll('>', '\"');
PIString cf = cur_file, ifc = d.takeRange('\"', '\"');
@@ -1070,13 +1351,23 @@ bool PICodeParser::parseDirective(PIString d) {
}
if (dname == s_define) {
PIString mname = d.takeCWord();
//piCout << mname;
// piCout << mname;
if (mname == s_PIMETA) return true;
if (d.left(1) == PIChar('(')) { // macro
PIStringList args = d.takeRange('(', ')').split(',').trim();
for (int i = 0; i < macros.size_s(); ++i)
if (macros[i].name == mname) {
macros.remove(i);
break;
}
macros << Macro(mname, d.trim(), args);
} else { // define
d.trim();
for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) {
defines.remove(i);
break;
}
defines << Define(mname, d);
evaluator.setVariable(mname, complexd_1);
}
@@ -1085,7 +1376,10 @@ bool PICodeParser::parseDirective(PIString d) {
if (dname == s_undef) {
PIString mname = d.takeCWord();
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;

View File

@@ -1,50 +1,63 @@
/*! @file picodeparser.h
* @brief C++ code parser
*/
/*! \file picodeparser.h
* \ingroup Code
* \~\brief
* \~english C++ code parser
* \~russian Разбор C++ кода
*/
/*
PIP - Platform Independent Primitives
C++ code parser
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
C++ code 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 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.
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/>.
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 PICODEPARSER_H
#define PICODEPARSER_H
#include "pifile.h"
#include "pievaluator.h"
#include "pifile.h"
inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));}
inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);}
inline bool _isCChar(const PIChar & c) {
return (c.isAlpha() || (c.toAscii() == '_'));
}
inline bool _isCChar(const PIString & c) {
if (c.isEmpty()) return false;
return _isCChar(c[0]);
}
class PIP_EXPORT PICodeParser {
public:
PICodeParser();
enum Visibility {Global, Public, Protected, Private};
enum Visibility {
Global,
Public,
Protected,
Private
};
enum Attribute {
NoAttributes = 0x0,
Const = 0x01,
Static = 0x02,
Mutable = 0x04,
Volatile = 0x08,
Inline = 0x10,
Virtual = 0x20,
Extern = 0x40
Const = 0x01,
Static = 0x02,
Mutable = 0x04,
Volatile = 0x08,
Inline = 0x10,
Virtual = 0x20,
Extern = 0x40
};
typedef PIFlags<Attribute> Attributes;
typedef PIPair<PIString, PIString> Define;
typedef PIPair<PIString, PIString> Typedef;
@@ -52,25 +65,25 @@ public:
struct PIP_EXPORT Macro {
Macro(const PIString & n = PIString(), const PIString & v = PIString(), const PIStringList & a = PIStringList()) {
name = n;
name = n;
value = v;
args = a;
args = a;
}
PIString expand(PIString args_, bool * ok = 0) const;
PIString name;
PIString value;
PIStringList args;
};
struct PIP_EXPORT Member {
Member() {
visibility = Global;
size = 0;
bits = -1;
visibility = Global;
size = 0;
bits = -1;
is_type_ptr = false;
attributes = NoAttributes;
attributes = NoAttributes;
}
bool isBitfield() const {return bits > 0;}
bool isBitfield() const { return bits > 0; }
MetaMap meta;
PIString type;
PIString name;
@@ -83,12 +96,12 @@ public:
int size;
int bits;
};
struct PIP_EXPORT Entity {
Entity() {
visibility = Global;
has_name = true;
size = 0;
visibility = Global;
has_name = true;
size = 0;
parent_scope = 0;
}
MetaMap meta;
@@ -99,56 +112,59 @@ public:
int size;
bool has_name;
Entity * parent_scope;
PIVector<Entity * > parents;
PIVector<Entity * > children;
PIVector<Entity *> parents;
PIVector<Entity *> children;
PIVector<Member> functions;
PIVector<Member> members;
PIVector<Typedef> typedefs;
};
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;
PIString name;
int value;
};
struct PIP_EXPORT Enum {
Enum(const PIString & n = PIString()) {
name = n;
}
Enum(const PIString & n = PIString()) { name = n; }
MetaMap meta;
PIString name;
PIVector<EnumeratorInfo> members;
};
void parseFile(const PIString & file, bool follow_includes = true);
void parseFiles(const PIStringList & files, bool follow_includes = true);
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 parseFileContent(PIString fc);
void includeDirectory(const PIString & dir) { includes << dir; }
void addDefine(const PIString & def_name, const PIString & def_value) { custom_defines << Define(def_name, def_value); }
bool isEnum(const PIString & name);
Entity * findEntityByName(const PIString & en);
PIStringList parsedFiles() const {return PIStringList(proc_files.toVector());}
PIString mainFile() const {return main_file;}
const PICodeParser::Entity * global() const {return &root_;}
int macrosSubstitutionMaxIterations() const {return macros_iter;}
void setMacrosSubstitutionMaxIterations(int value) {macros_iter = value;}
PIStringList parsedFiles() const { return PIStringList(proc_files.toVector()); }
PIString mainFile() const { return main_file; }
const PICodeParser::Entity * global() const { return &root_; }
int macrosSubstitutionMaxIterations() const { return macros_iter; }
void setMacrosSubstitutionMaxIterations(int value) { macros_iter = value; }
PIVector<Define> defines, custom_defines;
PIVector<Macro> macros;
PIVector<Enum> enums;
PIVector<Typedef> typedefs;
PIVector<Entity * > entities;
PIVector<Entity *> entities;
private:
void clear();
bool parseFileInternal(const PIString & file, bool follow_includes);
bool parseFileContent(PIString & fc, bool main);
bool parseDirective(PIString d);
Entity * parseClassDeclaration(const PIString & fc);
PIString parseClass(Entity * parent, PIString & fc);
void parseClass(Entity * parent, PIString & fc, bool is_namespace);
MetaMap parseMeta(PIString & fc);
bool parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta);
Typedef parseTypedef(PIString fc);
@@ -166,7 +182,7 @@ private:
bool isDeclaration(const PIString & fc, int start, int * end);
bool isMainFile(const PIString & fc);
void normalizeEntityNamespace(PIString & n);
int macros_iter, anon_num;
bool with_includes;
PIEvaluator evaluator;
@@ -178,7 +194,6 @@ private:
PIString cur_namespace;
PIMap<PIString, PIString> tmp_temp;
PIMap<PIString, MetaMap> tmp_meta;
};
#endif // PICODEPARSER_H

View File

@@ -1,33 +1,76 @@
/*! @file picompress.h
* @brief Compress class using zlib
*/
/*! \file picompress.h
* \brief
* \ingroup Compress
* \~\brief
* \~english Compress class zlib
* \~russian Сжатие с помощью zlib
*/
/*
PIP - Platform Independent Primitives
Compress class using zlib
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Compress class using zlib
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 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.
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/>.
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 Compress Compress
//! \~\brief
//! \~english Compression support
//! \~russian Поддержка сжатия
//!
//! \~\details
//! \~english \section cmake_module_Compress Building with CMake
//! \~russian \section cmake_module_Compress Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::Compress)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides simple compression and decompression support.
//!
//! \~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 PICOMPRESS_H
#define PICOMPRESS_H
#include "pip_compress_export.h"
#include "pibytearray.h"
#include "pip_compress_export.h"
//! \~english Compress "ba" with compression level "level", return empty %PIByteArray if no compression supports
//! \~russian Сжимает "ba" с уровнем сжатия "level", возвращает пустой %PIByteArray если нет поддержки
//! \~\ingroup Compress
//! \~\details
PIP_COMPRESS_EXPORT PIByteArray piCompress(const PIByteArray & ba, int level = 6);
//! \~english Decompress "zba", return empty %PIByteArray if no compression supports
//! \~russian Распаковывает "zba", возвращает пустой %PIByteArray если нет поддержки
//! \~\ingroup Compress
//! \~\details
PIP_COMPRESS_EXPORT PIByteArray piDecompress(const PIByteArray & zba);
#endif // PICOMPRESS_H

View File

@@ -1,21 +1,52 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Module includes
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 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.
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/>.
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 Console Console
//! \~\brief
//! \~english Console graphic
//! \~russian Графика в консоли
//!
//! \~\details
//! \~english \section cmake_module_Console Building with CMake
//! \~russian \section cmake_module_Console Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::Console)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides grab keyboard from console, simple tiling manager and virtual terminal.
//!
//! \~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 PICONSOLEMODULE_H
#define PICONSOLEMODULE_H

View File

@@ -1,31 +1,34 @@
/*
PIP - Platform Independent Primitives
Keyboard grabber for console
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Keyboard grabber for console
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 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.
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/>.
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 "piincludes_p.h"
#include "pikbdlistener.h"
#include "piincludes_p.h"
#include "piliterals.h"
#ifndef WINDOWS
# include <termios.h>
#else
# include <wincon.h>
# include <wingdi.h>
#endif
/** \class PIKbdListener
* @brief Keyboard console input listener
* \brief Keyboard console input listener
* \details This class provide listening of console keyboard input.
* There is two ways to receive pressed key:
* * external static function with format "void func(char key, void * data_)"
@@ -46,80 +49,82 @@ PIKbdListener * PIKbdListener::_object = 0;
#ifndef WINDOWS
// unix
const PIKbdListener::EscSeq PIKbdListener::esc_seq[] = {
{"OA", PIKbdListener::UpArrow, 0, 0 , 1 },
{"OA", PIKbdListener::UpArrow, 4, 0 , 0 },
{"[1A", PIKbdListener::UpArrow, 0, 0 , 0 },
{"[A", PIKbdListener::UpArrow, 0, vt_all , 0 },
{"OB", PIKbdListener::DownArrow, 0, 0 , 1 },
{"OB", PIKbdListener::DownArrow, 4, 0 , 0 },
{"[1B", PIKbdListener::DownArrow, 0, 0 , 0 },
{"[B", PIKbdListener::DownArrow, 0, vt_all , 0 },
{"OC", PIKbdListener::RightArrow, 0, 0 , 1 },
{"OC", PIKbdListener::RightArrow, 4, 0 , 0 },
{"[1C", PIKbdListener::RightArrow, 0, 0 , 0 },
{"[C", PIKbdListener::RightArrow, 0, vt_all , 0 },
{"OD", PIKbdListener::LeftArrow, 0, 0 , 1 },
{"OD", PIKbdListener::LeftArrow, 4, 0 , 0 },
{"[1D", PIKbdListener::LeftArrow, 0, 0 , 0 },
{"[D", PIKbdListener::LeftArrow, 0, vt_all , 0 },
{"[H", PIKbdListener::Home, 0, vt_xterm , 0 },
{"[1H", PIKbdListener::Home, 0, 0 , 0 },
{"OH", PIKbdListener::Home, 0, 0 , 1 },
{"[1~", PIKbdListener::Home, 0, vt_linux , 0 },
{"[F", PIKbdListener::End, 0, vt_xterm , 0 },
{"[1F", PIKbdListener::End, 0, 0 , 0 },
{"OF", PIKbdListener::End, 0, 0 , 1 },
{"[4~", PIKbdListener::End, 0, vt_linux , 0 },
{"[2~", PIKbdListener::Insert, 0, vt_all , 0 },
{"[3~", PIKbdListener::Delete, 0, vt_all , 0 },
{"[5~", PIKbdListener::PageUp, 0, vt_all , 0 },
{"[6~", PIKbdListener::PageDown, 0, vt_all , 0 },
{"[Z", PIKbdListener::Tab, 1, vt_xterm , 0 },
{"OP", PIKbdListener::F1, 0, vt_xterm , 0 },
{"[[A", PIKbdListener::F1, 0, vt_linux , 0 },
{"[11~", PIKbdListener::F1, 0, 0 , 0 },
{"[25~", PIKbdListener::F1, 1, vt_linux , 0 },
{"OQ", PIKbdListener::F2, 0, vt_xterm , 0 },
{"[[B", PIKbdListener::F2, 0, vt_linux , 0 },
{"[12~", PIKbdListener::F2, 0, 0 , 0 },
{"[26~", PIKbdListener::F2, 1, vt_linux , 0 },
{"OR", PIKbdListener::F3, 0, vt_xterm , 0 },
{"[[C", PIKbdListener::F3, 0, vt_linux , 0 },
{"[13~", PIKbdListener::F3, 0, 0 , 0 },
{"[28~", PIKbdListener::F3, 1, vt_linux , 0 },
{"OS", PIKbdListener::F4, 0, vt_xterm , 0 },
{"[[D", PIKbdListener::F4, 0, vt_linux , 0 },
{"[14~", PIKbdListener::F4, 0, 0 , 0 },
{"[29~", PIKbdListener::F4, 1, vt_linux , 0 },
{"[[E", PIKbdListener::F5, 0, vt_linux , 0 },
{"OT", PIKbdListener::F5, 0, 0 , 0 },
{"[15~", PIKbdListener::F5, 0, vt_xterm , 0 },
{"[31~", PIKbdListener::F5, 1, vt_linux , 0 },
{"OU", PIKbdListener::F6, 0, 0 , 0 },
{"[17~", PIKbdListener::F6, 0, vt_all , 0 },
{"[32~", PIKbdListener::F6, 1, vt_linux , 0 },
{"OV", PIKbdListener::F7, 0, 0 , 0 },
{"[18~", PIKbdListener::F7, 0, vt_all , 0 },
{"[33~", PIKbdListener::F7, 1, vt_linux , 0 },
{"OW", PIKbdListener::F8, 0, 0 , 0 },
{"[19~", PIKbdListener::F8, 0, vt_all , 0 },
{"[34~", PIKbdListener::F8, 1, vt_linux , 0 },
{"OX", PIKbdListener::F9, 0, 0 , 0 },
{"[20~", PIKbdListener::F9, 0, vt_all , 0 },
{"[35~", PIKbdListener::F9, 1, vt_linux , 0 },
{"OY", PIKbdListener::F10, 0, 0 , 0 },
{"[21~", PIKbdListener::F10, 0, vt_all , 0 },
{"[36~", PIKbdListener::F10, 1, vt_linux , 0 },
{"OZ", PIKbdListener::F11, 0, 0 , 0 },
{"[23~", PIKbdListener::F11, 0, vt_all , 0 },
{"O[", PIKbdListener::F12, 0, 0 , 0 },
{"[24~", PIKbdListener::F12, 0, vt_all , 0 },
// End
{0, 0, 0, 0, 0},
{"OA", PIKbdListener::UpArrow, 0, 0, 1},
{"OA", PIKbdListener::UpArrow, 4, 0, 0},
{"[1A", PIKbdListener::UpArrow, 0, 0, 0},
{"[A", PIKbdListener::UpArrow, 0, vt_all, 0},
{"OB", PIKbdListener::DownArrow, 0, 0, 1},
{"OB", PIKbdListener::DownArrow, 4, 0, 0},
{"[1B", PIKbdListener::DownArrow, 0, 0, 0},
{"[B", PIKbdListener::DownArrow, 0, vt_all, 0},
{"OC", PIKbdListener::RightArrow, 0, 0, 1},
{"OC", PIKbdListener::RightArrow, 4, 0, 0},
{"[1C", PIKbdListener::RightArrow, 0, 0, 0},
{"[C", PIKbdListener::RightArrow, 0, vt_all, 0},
{"OD", PIKbdListener::LeftArrow, 0, 0, 1},
{"OD", PIKbdListener::LeftArrow, 4, 0, 0},
{"[1D", PIKbdListener::LeftArrow, 0, 0, 0},
{"[D", PIKbdListener::LeftArrow, 0, vt_all, 0},
{"[H", PIKbdListener::Home, 0, vt_xterm, 0},
{"[1H", PIKbdListener::Home, 0, 0, 0},
{"OH", PIKbdListener::Home, 0, 0, 1},
{"[1~", PIKbdListener::Home, 0, vt_linux, 0},
{"[F", PIKbdListener::End, 0, vt_xterm, 0},
{"[1F", PIKbdListener::End, 0, 0, 0},
{"OF", PIKbdListener::End, 0, 0, 1},
{"[4~", PIKbdListener::End, 0, vt_linux, 0},
{"[2~", PIKbdListener::Insert, 0, vt_all, 0},
{"[3~", PIKbdListener::Delete, 0, vt_all, 0},
{"[5~", PIKbdListener::PageUp, 0, vt_all, 0},
{"[6~", PIKbdListener::PageDown, 0, vt_all, 0},
{"[Z", PIKbdListener::Tab, 1, vt_xterm, 0},
{"OP", PIKbdListener::F1, 0, vt_xterm, 0},
{"[[A", PIKbdListener::F1, 0, vt_linux, 0},
{"[11~", PIKbdListener::F1, 0, 0, 0},
{"[25~", PIKbdListener::F1, 1, vt_linux, 0},
{"OQ", PIKbdListener::F2, 0, vt_xterm, 0},
{"[[B", PIKbdListener::F2, 0, vt_linux, 0},
{"[12~", PIKbdListener::F2, 0, 0, 0},
{"[26~", PIKbdListener::F2, 1, vt_linux, 0},
{"OR", PIKbdListener::F3, 0, vt_xterm, 0},
{"[[C", PIKbdListener::F3, 0, vt_linux, 0},
{"[13~", PIKbdListener::F3, 0, 0, 0},
{"[28~", PIKbdListener::F3, 1, vt_linux, 0},
{"OS", PIKbdListener::F4, 0, vt_xterm, 0},
{"[[D", PIKbdListener::F4, 0, vt_linux, 0},
{"[14~", PIKbdListener::F4, 0, 0, 0},
{"[29~", PIKbdListener::F4, 1, vt_linux, 0},
{"[[E", PIKbdListener::F5, 0, vt_linux, 0},
{"OT", PIKbdListener::F5, 0, 0, 0},
{"[15~", PIKbdListener::F5, 0, vt_xterm, 0},
{"[31~", PIKbdListener::F5, 1, vt_linux, 0},
{"OU", PIKbdListener::F6, 0, 0, 0},
{"[17~", PIKbdListener::F6, 0, vt_all, 0},
{"[32~", PIKbdListener::F6, 1, vt_linux, 0},
{"OV", PIKbdListener::F7, 0, 0, 0},
{"[18~", PIKbdListener::F7, 0, vt_all, 0},
{"[33~", PIKbdListener::F7, 1, vt_linux, 0},
{"OW", PIKbdListener::F8, 0, 0, 0},
{"[19~", PIKbdListener::F8, 0, vt_all, 0},
{"[34~", PIKbdListener::F8, 1, vt_linux, 0},
{"OX", PIKbdListener::F9, 0, 0, 0},
{"[20~", PIKbdListener::F9, 0, vt_all, 0},
{"[35~", PIKbdListener::F9, 1, vt_linux, 0},
{"OY", PIKbdListener::F10, 0, 0, 0},
{"[21~", PIKbdListener::F10, 0, vt_all, 0},
{"[36~", PIKbdListener::F10, 1, vt_linux, 0},
{"OZ", PIKbdListener::F11, 0, 0, 0},
{"[23~", PIKbdListener::F11, 0, vt_all, 0},
{"O[", PIKbdListener::F12, 0, 0, 0},
{"[24~", PIKbdListener::F12, 0, vt_all, 0},
// End
{0, 0, 0, 0, 0},
};
void setupTerminal(bool on) {
printf("\e[?1000"); printf(on ? "h" : "l");
printf("\e[?1002"); printf(on ? "h" : "l");
printf("\e[?1000");
printf(on ? "h" : "l");
printf("\e[?1002");
printf(on ? "h" : "l");
fflush(0);
}
#endif
@@ -127,7 +132,7 @@ void setupTerminal(bool on) {
PRIVATE_DEFINITION_START(PIKbdListener)
#ifdef WINDOWS
void * hIn, * hOut;
void *hIn, *hOut;
DWORD smode, tmode;
CONSOLE_SCREEN_BUFFER_INFO sbi;
#else
@@ -138,24 +143,24 @@ PRIVATE_DEFINITION_START(PIKbdListener)
#else
int
#endif
ret;
ret;
PRIVATE_DEFINITION_END(PIKbdListener)
PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() {
setName("keyboard_listener");
setName("keyboard_listener"_a);
_object = this;
#ifdef WINDOWS
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(PRIVATE->hIn, &PRIVATE->smode);
#else
tcgetattr(0, &PRIVATE->sterm);
#endif
is_active = true;
ret_func = slot;
kbddata_ = _d;
dbl_interval = 400;
is_active = true;
ret_func = slot;
kbddata_ = _d;
dbl_interval = 400;
PIKbdListener::exiting = exit_enabled = false;
if (startNow) start();
}
@@ -190,9 +195,9 @@ PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
bool shi = v & SHIFT_PRESSED;
bool alt = v & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
if (ctrl) ret |= PIKbdListener::Ctrl;
if (shi) ret |= PIKbdListener::Shift;
if (alt) ret |= PIKbdListener::Alt;
//if (meta) ret |= PIKbdListener::Meta;
if (shi) ret |= PIKbdListener::Shift;
if (alt) ret |= PIKbdListener::Alt;
// if (meta) ret |= PIKbdListener::Meta;
if (v & CAPSLOCK_ON) shi = !shi;
if (shift) *shift = shi;
return ret;
@@ -200,7 +205,7 @@ PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
PIKbdListener::MouseButtons getButtons(DWORD v) {
PIKbdListener::MouseButtons ret;
if (v & FROM_LEFT_1ST_BUTTON_PRESSED) ret |= PIKbdListener::MouseLeft;
if (v & RIGHTMOST_BUTTON_PRESSED) ret |= PIKbdListener::MouseRight;
if (v & RIGHTMOST_BUTTON_PRESSED) ret |= PIKbdListener::MouseRight;
if (v & FROM_LEFT_2ND_BUTTON_PRESSED) ret |= PIKbdListener::MouseMiddle;
return ret;
}
@@ -208,77 +213,160 @@ PIKbdListener::MouseButtons getButtons(DWORD v) {
void PIKbdListener::readKeyboard() {
ke.key = 0;
ke.key = 0;
ke.modifiers = 0;
memset(rc, 0, 8);
#ifdef WINDOWS
INPUT_RECORD ir;
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
//piCout << ir.EventType;
// piCout << ir.EventType;
switch (ir.EventType) {
case KEY_EVENT: {
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
if (ker.bKeyDown) {
bool shift = false;
bool shift = false;
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) {
case 8: PRIVATE->ret = 1; ke.key = Backspace; break;
case 33: PRIVATE->ret = 1; ke.key = PageUp; break;
case 34: PRIVATE->ret = 1; 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 8:
PRIVATE->ret = 1;
ke.key = Backspace;
break;
case 33:
PRIVATE->ret = 1;
ke.key = PageUp;
break;
case 34:
PRIVATE->ret = 1;
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 '\n': PRIVATE->ret = 1; ke.key = Return; break;
case ' ': PRIVATE->ret = 1; ke.key = Space; break;
case '\t': PRIVATE->ret = 1; ke.key = Tab; break;
case 112: PRIVATE->ret = 1; 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;
case '\n':
PRIVATE->ret = 1;
ke.key = Return;
break;
case ' ':
PRIVATE->ret = 1;
ke.key = Space;
break;
case '\t':
PRIVATE->ret = 1;
ke.key = Tab;
break;
case 112:
PRIVATE->ret = 1;
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:
PRIVATE->ret = 1;
rc[0] = 1;
rc[0] = 1;
{
PIChar ch = PIChar::fromConsole(ker.uChar.AsciiChar);
if (shift) ch = ch.toUpper();
ke.key = ch.unicode16Code();
PIChar ch = PIChar::fromConsole(ker.uChar.AsciiChar);
if (shift) ch = ch.toUpper();
ke.key = ch.unicode16Code();
}
break;
}
if (ke.key == 0) {piMSleep(10); return;}
} else {piMSleep(10); return;}
if (ke.key == 0) {
piMSleep(10);
return;
}
} else {
piMSleep(10);
return;
}
break;
} break;
case MOUSE_EVENT: {
MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent;
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
me.modifiers = getModifiers(mer.dwControlKeyState);
me.modifiers = getModifiers(mer.dwControlKeyState);
MouseButtons mb = getButtons(mer.dwButtonState);
if (mer.dwEventFlags & MOUSE_WHEELED) {
memcpy((void*)(&we), (const void*)(&me), sizeof(me));
we.action = MouseWheel;
memcpy((void *)(&we), (const void *)(&me), sizeof(me));
we.action = MouseWheel;
we.direction = short((mer.dwButtonState >> 8) & 0xFFFF) > 0;
//piCout << "wheel" << we.direction;
// piCout << "wheel" << we.direction;
wheelEvent(we, kbddata_);
break;
} else {
me.x = mer.dwMousePosition.X;
me.y = mer.dwMousePosition.Y - PRIVATE->sbi.srWindow.Top;
me.x = mer.dwMousePosition.X;
me.y = mer.dwMousePosition.Y - PRIVATE->sbi.srWindow.Top;
bool move = mer.dwEventFlags & MOUSE_MOVED;
if (move) {
if (me.action == MouseButtonRelease) {
@@ -296,38 +384,49 @@ void PIKbdListener::readKeyboard() {
prev_p_me = me;
}
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;
if (piCompareBinary(&prev_me, &me, sizeof(me)))
break;
memcpy((void*)(&prev_me), (const void*)(&me), sizeof(me));
//PIString _s[] = {"press", "release", "dbl click", "move"};
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
if (piCompareBinary(&prev_me, &me, sizeof(me))) break;
memcpy((void *)(&prev_me), (const void *)(&me), sizeof(me));
// PIString _s[] = {"press", "release", "dbl click", "move"};
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_);
break;
}
}
break;
default:
piMSleep(10);
return;
} break;
default: piMSleep(10); return;
}
#else
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
PRIVATE->ret = read(0, rc, 8);
/*piCout << "key" << PIString(rc).replaceAll("\e", "\\e");
for (int i = 0; i < PRIVATE->ret; ++i)
PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' ';
PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' ';
PICout(0) << "\n";
std::cout << PRIVATE->ret << " chars ";
for (int i = 0; i < PRIVATE->ret; ++i)
cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/
if (rc[0] == 0) {piMSleep(10); return;}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {piMSleep(10); return;}
if (PRIVATE->ret == 1) ke.key = PIChar::fromConsole(rc[0]).unicode16Code();
std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
std::cout << std::endl;*/
if (rc[0] == 0) {
piMSleep(10);
return;
}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {
piMSleep(10);
return;
}
if (PRIVATE->ret == 1) {
if (rc[0] == 8)
ke.key = Backspace;
else
ke.key = PIChar::fromConsole(rc[0]).unicode16Code();
}
int mod(0);
// 2 - shift 1
// 3 - alt 2
@@ -336,25 +435,26 @@ void PIKbdListener::readKeyboard() {
// 8 - ctrl+alt+shift 7
if (rc[0] == '\e') { // search for Alt
if (PRIVATE->ret == 2) {
mod = 2;
mod = 2;
ke.key = PIChar::fromConsole(rc[1]).unicode16Code();
} else {// escape-seq
} else { // escape-seq
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;
PRIVATE->ret--;
}
if (rc[1] == '[') {
if (rc[2] == 'M') { // mouse
if (PRIVATE->ret >= 5) {
me.x = uchar(rc[4] - '!');
me.y = uchar(rc[5] - '!');
me.x = uchar(rc[4] - '!');
me.y = uchar(rc[5] - '!');
int b = rc[3] & 0x7, a = rc[3] & 0x60;
if (a == 0x60) {
memcpy((void*)(&we), (const void*)(&me), sizeof(me));
we.action = MouseWheel;
memcpy((void *)(&we), (const void *)(&me), sizeof(me));
we.action = MouseWheel;
we.direction = (b == 0);
//piCout << "wheel" << we.direction;
// piCout << "wheel" << we.direction;
wheelEvent(we, kbddata_);
} else {
switch (b) {
@@ -365,7 +465,7 @@ void PIKbdListener::readKeyboard() {
}
if (a == 0x20) {
if (b == 3) {
me.action = MouseButtonRelease;
me.action = MouseButtonRelease;
me.buttons = 0;
} else {
if (tm_dbl.elapsed_m() <= dbl_interval && prev_p_me.x == me.x && prev_p_me.y == me.y)
@@ -378,18 +478,19 @@ void PIKbdListener::readKeyboard() {
}
}
if (a == 0x40) me.action = MouseMove;
//PIString _s[] = {"press", "release", "dbl click", "move"};
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
// PIString _s[] = {"press", "release", "dbl click", "move"};
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_);
}
//piCout << me.x << me.y << PICoutManipulators::Hex << b << a;
// piCout << me.x << me.y << PICoutManipulators::Hex << b << a;
}
return;
} else {
for (int i = 2; i < 7; ++i) // search for modifier
if (rc[i] == ';') {
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;
PRIVATE->ret -= 2;
break;
@@ -399,14 +500,15 @@ void PIKbdListener::readKeyboard() {
if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4)
if (rc[2] >= '1' && rc[2] <= '8') {
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;
PRIVATE->ret--;
}
}
for (int i = 0; ; ++i) {
for (int i = 0;; ++i) {
if (!esc_seq[i].seq) break;
//piCout << "search" << rc[1] << esc_seq[i].seq;
// piCout << "search" << rc[1] << esc_seq[i].seq;
if (strcmp(esc_seq[i].seq, &(rc[1])) == 0) {
ke.key = esc_seq[i].key;
mod |= esc_seq[i].mod;
@@ -418,18 +520,16 @@ void PIKbdListener::readKeyboard() {
if (mod & 0x1) ke.modifiers |= Shift;
if (mod & 0x2) ke.modifiers |= Alt;
if (mod & 0x4) ke.modifiers |= Ctrl;
//if (mod & 0x8) ke.modifiers |= Meta;
// if (mod & 0x8) ke.modifiers |= Meta;
}
/*cout << "wo mods (" << mod << ")\n";
for (int i = 0; i < PRIVATE->ret; ++i)
cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/
/*cout << "wo mods (" << mod << ")\n";
for (int i = 0; i < PRIVATE->ret; ++i)
cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/
}
if (ke.key == 0 && PRIVATE->ret > 1)
ke.key = PIChar(rc).unicode16Code();
if (ke.key == 0 && PRIVATE->ret > 1) ke.key = PIChar::fromSystem(rc).unicode16Code();
#endif
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1)
ke.key = Return;
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1) ke.key = Return;
if (exit_enabled && ke.key == exit_key) {
PIKbdListener::exiting = true;
return;
@@ -442,7 +542,7 @@ void PIKbdListener::readKeyboard() {
void PIKbdListener::end() {
//cout << "list end" << endl;
// cout << "list end" << endl;
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
#else

View File

@@ -1,84 +1,92 @@
/*! @file pikbdlistener.h
* @brief Keyboard console input listener
*/
/*! \file pikbdlistener.h
* \ingroup Console
* \~\brief
* \~english Keyboard console input listener
* \~russian Консольный захват клавиатуры
*/
/*
PIP - Platform Independent Primitives
Keyboard grabber for console
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Keyboard grabber for console
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 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.
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/>.
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 PIKBDLISTENER_H
#define PIKBDLISTENER_H
#include "pithread.h"
#include "pitime.h"
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5);
#define WAIT_FOR_EXIT \
while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); // TODO: rewrite with condvar
class PIP_EXPORT PIKbdListener: public PIThread
{
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
class PIP_EXPORT PIKbdListener: public PIThread {
PIOBJECT_SUBCLASS(PIKbdListener, PIThread);
friend class PIConsole;
friend class PITerminal;
public:
public:
//! Special keyboard keys
enum SpecialKey {
Tab /** Tab key */ = 0x09,
Return /** Enter key */ = 0x0a,
Esc /** Escape key */ = 0x1b,
Space /** Space key */ = 0x20,
Backspace /** Backspace key */ = 0x7f,
UpArrow /** Up arrow key */ = -1,
DownArrow /** Down arrow key */ = -2,
Tab /** Tab key */ = 0x09,
Return /** Enter key */ = 0x0a,
Esc /** Escape key */ = 0x1b,
Space /** Space key */ = 0x20,
Backspace /** Backspace key */ = 0x7f,
UpArrow /** Up arrow key */ = -1,
DownArrow /** Down arrow key */ = -2,
RightArrow /** Right arrow key */ = -3,
LeftArrow /** Left arrow key */ = -4,
Home /** Home key */ = -5,
End /** End key */ = -6,
PageUp /** Page up key */ = -7,
PageDown /** Page down key */ = -8,
Insert /** Delete key */ = -9,
Delete /** Delete key */ = -10,
F1 /** F1 key */ = -11,
F2 /** F2 key */ = -12,
F3 /** F3 key */ = -13,
F4 /** F4 key */ = -14,
F5 /** F5 key */ = -15,
F6 /** F6 key */ = -16,
F7 /** F7 key */ = -17,
F8 /** F8 key */ = -18,
F9 /** F9 key */ = -19,
F10 /** F10 key */ = -20,
F11 /** F11 key */ = -21,
F12 /** F12 key */ = -22
LeftArrow /** Left arrow key */ = -4,
Home /** Home key */ = -5,
End /** End key */ = -6,
PageUp /** Page up key */ = -7,
PageDown /** Page down key */ = -8,
Insert /** Delete key */ = -9,
Delete /** Delete key */ = -10,
F1 /** F1 key */ = -11,
F2 /** F2 key */ = -12,
F3 /** F3 key */ = -13,
F4 /** F4 key */ = -14,
F5 /** F5 key */ = -15,
F6 /** F6 key */ = -16,
F7 /** F7 key */ = -17,
F8 /** F8 key */ = -18,
F9 /** F9 key */ = -19,
F10 /** F10 key */ = -20,
F11 /** F11 key */ = -21,
F12 /** F12 key */ = -22
};
//! Keyboard modifiers
enum KeyModifier {
Ctrl /** Control key */ = 0x1,
Shift /** Shift key */ = 0x2,
Alt /** Alt key */ = 0x4
//Meta /** Meta (windows) key */ = 0x8
Shift /** Shift key */ = 0x2,
Alt /** Alt key */ = 0x4
// Meta /** Meta (windows) key */ = 0x8
};
typedef PIFlags<KeyModifier> KeyModifiers;
//! This struct contains information about pressed keyboard key
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)
int key;
@@ -89,8 +97,8 @@ public:
//! Mouse buttons
enum MouseButton {
MouseLeft /** Left button */ = 0x01,
MouseRight /** Right button */ = 0x02,
MouseLeft /** Left button */ = 0x01,
MouseRight /** Right button */ = 0x02,
MouseMiddle /** Middle button */ = 0x04
};
@@ -107,7 +115,12 @@ public:
//! This struct contains information about mouse action
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
int x;
@@ -127,7 +140,7 @@ public:
//! This struct contains information about mouse wheel action
struct PIP_EXPORT WheelEvent: public MouseEvent {
WheelEvent(): MouseEvent() {direction = false;}
WheelEvent(): MouseEvent() { direction = false; }
//! Wheel direction, /b true - up, /b fasle - down
bool direction;
@@ -142,69 +155,74 @@ public:
//! Returns custom data
void * data() {return kbddata_;}
void * data() { return kbddata_; }
//! Set custom data to "_data"
void setData(void * _data) {kbddata_ = _data;}
void setData(void * _data) { kbddata_ = _data; }
//! Set external function to "slot"
void setSlot(KBFunc slot) {ret_func = slot;}
void setSlot(KBFunc slot) { ret_func = 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
bool exitCaptured() const {return exit_enabled;}
bool exitCaptured() const { return exit_enabled; }
//! Returns exit key, default 'Q'
int exitKey() const {return exit_key;}
int exitKey() const { return exit_key; }
double doubleClickInterval() const {return dbl_interval;}
void setDoubleClickInterval(double v) {dbl_interval = v;}
double doubleClickInterval() const { return dbl_interval; }
void setDoubleClickInterval(double v) { dbl_interval = v; }
void readKeyboard();
//! 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_HANDLER1(void, enableExitCapture, int, key) {exit_enabled = true; exit_key = key;}
EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;}
EVENT_HANDLER(void, setActive) {setActive(true);}
EVENT_HANDLER(void, enableExitCapture) { enableExitCapture('Q'); }
EVENT_HANDLER1(void, enableExitCapture, int, key) {
exit_enabled = true;
exit_key = key;
}
EVENT_HANDLER(void, disableExitCapture) { exit_enabled = false; }
EVENT_HANDLER(void, setActive) { setActive(true); }
EVENT_HANDLER1(void, setActive, bool, yes);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data)
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data)
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data);
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void *, data);
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void *, data);
//! \handlers
//! \{
//! \handlers
//! \{
//! \fn void enableExitCapture(int key = 'Q')
//! @brief Enable exit key "key" awaiting
//! \brief Enable exit key "key" awaiting
//! \fn void disableExitCapture()
//! @brief Disable exit key awaiting
//! \brief Disable exit key awaiting
//! \fn void setActive(bool yes = true)
//! @brief Set keyboard listening is active or not
//! \brief Set keyboard listening is active or not
//! \}
//! \events
//! \{
//! \}
//! \events
//! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! @brief Raise on key "key" pressed, "data" is custom data
//! \brief Raise on key "key" pressed, "data" is custom data
//! \}
//! \}
static bool exiting;
static PIKbdListener * instance() {return _object;}
static PIKbdListener * instance() { return _object; }
private:
void begin();
void run() {readKeyboard();}
void end();
void begin() override;
void run() override { readKeyboard(); }
void end() override;
#ifndef WINDOWS
struct PIP_EXPORT EscSeq {
@@ -222,7 +240,7 @@ private:
vt_none,
vt_xterm = 0x1,
vt_linux = 0x2,
vt_all = 0xFF
vt_all = 0xFF
};
static const EscSeq esc_seq[];
@@ -240,17 +258,42 @@ private:
MouseEvent me, prev_me, prev_p_me;
WheelEvent we;
static PIKbdListener * _object;
};
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << v.modifiers; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::MouseEvent & v) {s << v.x << v.y << (int)v.action << v.buttons << v.modifiers; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::WheelEvent & v) {s << (*(PIKbdListener::MouseEvent*)&v) << (uchar)v.direction; return s;}
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {
s << v.x << v.y << v.action << v.buttons << v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::MouseEvent) {
s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {
s << (*(PIKbdListener::MouseEvent *)&v) << v.direction;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::WheelEvent) {
s >> (*(PIKbdListener::MouseEvent *)&v) >> v.direction;
return s;
}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {s >> v.key >> v.modifiers; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::MouseEvent & v) {int a(0); s >> v.x >> v.y >> a >> v.buttons >> v.modifiers; v.action = (PIKbdListener::MouseAction)a; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::WheelEvent & v) {uchar d(0); s >> (*(PIKbdListener::MouseEvent*)&v) >> d; v.direction = d; return s;}
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)

View File

@@ -1,105 +1,112 @@
/*! @file piscreen.h
* @brief Console GUI class
*/
/*! \file piscreen.h
* \ingroup Console
* \~\brief
* \~english Console tiling manager
* \~russian Консольный тайловый менеджер
*/
/*
PIP - Platform Independent Primitives
Console GUI
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Console GUI
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 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.
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/>.
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 PISCREEN_H
#define PISCREEN_H
#include "pip_console_export.h"
#include "piscreentile.h"
#include "piscreendrawer.h"
#include "piscreentile.h"
class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
{
PIOBJECT_SUBCLASS(PIScreen, PIThread)
class PIP_CONSOLE_EXPORT PIScreen
: public PIThread
, public PIScreenTypes::PIScreenBase {
PIOBJECT_SUBCLASS(PIScreen, PIThread);
class SystemConsole;
public:
//! Constructs %PIScreen with key handler "slot" and if "startNow" start it
PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
~PIScreen();
//! Directly call function from \a PIKbdListener
void enableExitCapture(int key = 'Q') {listener->enableExitCapture(key);}
//! Directly call function from \a PIKbdListener
void disableExitCapture() {listener->disableExitCapture();}
//! Directly call function from \a PIKbdListener
bool exitCaptured() const {return listener->exitCaptured();}
//! Directly call function from \a PIKbdListener
int exitKey() const {return listener->exitKey();}
int windowWidth() const {return console.width;}
int windowHeight() const {return console.height;}
bool isMouseEnabled() const {return mouse_;}
~PIScreen();
//! Directly call function from \a PIKbdListener
void enableExitCapture(int key = 'Q') { listener->enableExitCapture(key); }
//! Directly call function from \a PIKbdListener
void disableExitCapture() { listener->disableExitCapture(); }
//! Directly call function from \a PIKbdListener
bool exitCaptured() const { return listener->exitCaptured(); }
//! Directly call function from \a PIKbdListener
int exitKey() const { return listener->exitKey(); }
int windowWidth() const { return console.width; }
int windowHeight() const { return console.height; }
bool isMouseEnabled() const { return mouse_; }
void setMouseEnabled(bool on);
PIScreenTile * rootTile() {return &root;}
PIScreenTile * rootTile() { return &root; }
PIScreenTile * tileByName(const PIString & name);
void setDialogTile(PIScreenTile * t);
PIScreenTile * dialogTile() const {return tile_dialog;}
PIScreenDrawer * drawer() {return &drawer_;}
void clear() {drawer_.clear();}
void resize(int w, int h) {console.resize(w, h);}
PIScreenTile * dialogTile() const { return tile_dialog; }
PIScreenDrawer * drawer() { return &drawer_; }
void clear() { drawer_.clear(); }
void resize(int w, int h) { console.resize(w, h); }
EVENT_HANDLER0(void, waitForFinish);
EVENT_HANDLER0(void, start) {start(false);}
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
EVENT_HANDLER0(void, stop) {stop(false);}
EVENT_HANDLER0(void, start) { start(false); }
EVENT_HANDLER1(void, start, bool, wait) {
PIThread::start(40);
if (wait) waitForFinish();
}
EVENT_HANDLER0(void, stop) { stop(false); }
EVENT_HANDLER1(void, stop, bool, clear);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
//! \handlers
//! \{
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data);
EVENT2(tileEvent, PIScreenTile *, tile, PIScreenTypes::TileEvent, e);
//! \handlers
//! \{
//! \fn void waitForFinish()
//! @brief block until finished (exit key will be pressed)
//! \brief block until finished (exit key will be pressed)
//! \fn void start(bool wait = false)
//! @brief Start console output and if "wait" block until finished (exit key will be pressed)
//! \brief Start console output and if "wait" block until finished (exit key will be pressed)
//! \fn void stop(bool clear = false)
//! @brief Stop console output and if "clear" clear the screen
//! \}
//! \events
//! \{
//! \brief Stop console output and if "clear" clear the screen
//! \}
//! \events
//! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! @brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
//! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e)
//! @brief Raise on some event "e" from tile "tile"
//! \}
//! \brief Raise on some event "e" from tile "tile"
//! \}
private:
class PIP_CONSOLE_EXPORT SystemConsole {
public:
@@ -128,23 +135,23 @@ private:
PRIVATE_DECLARATION(PIP_CONSOLE_EXPORT)
int width, height, pwidth, pheight;
int mouse_x, mouse_y;
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
PIVector<PIVector<PIScreenTypes::Cell>> cells, pcells;
};
void begin();
void run();
void end();
void begin() override;
void run() override;
void end() override;
void key_event(PIKbdListener::KeyEvent key);
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);}
PIVector<PIScreenTile*> tiles() {return root.children();}
PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
static void key_eventS(PIKbdListener::KeyEvent key, void * t) { ((PIScreen *)t)->key_event(key); }
PIVector<PIScreenTile *> tiles() { return root.children(); }
PIVector<PIScreenTile *> prepareMouse(PIKbdListener::MouseEvent * e);
PIVector<PIScreenTile *> tilesUnderMouse(int x, int y);
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
void tileRemovedInternal(PIScreenTile * t);
void tileSetFocusInternal(PIScreenTile * t);
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e) override;
void tileRemovedInternal(PIScreenTile * t) override;
void tileSetFocusInternal(PIScreenTile * t) override;
bool mouse_;
SystemConsole console;
@@ -152,8 +159,7 @@ private:
PIKbdListener * listener;
PIKbdListener::KBFunc ret_func;
PIScreenTile root;
PIScreenTile * tile_focus, * tile_dialog;
PIScreenTile *tile_focus, *tile_dialog;
};

View File

@@ -1,25 +1,26 @@
/*! @file piscreenconsole.h
* @brief Tile for PIScreen with PIConsole API
*
* This file declares TileVars
*/
/*! \file piscreenconsole.h
* \ingroup Console
* \~\brief
* \~english Tile for PIScreen with PIConsole API
* \~russian Тайл для PIScreen с API PIConsole
*/
/*
PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API
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 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.
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/>.
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 PISCREENCONSOLE_H
@@ -34,10 +35,15 @@
class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile {
public:
TileVars(const PIString & n = PIString());
protected:
struct PIP_CONSOLE_EXPORT Variable {
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = PIScreenTypes::CellFormat(); ptr = 0;}
bool isEmpty() const {return (ptr == 0);}
Variable() {
nx = ny = type = offset = bitFrom = bitCount = size = 0;
format = PIScreenTypes::CellFormat();
ptr = 0;
}
bool isEmpty() const { return (ptr == 0); }
PIString name;
PIScreenTypes::CellFormat format;
int nx;
@@ -49,28 +55,26 @@ protected:
int size;
const void * ptr;
/*void operator =(const Variable & src) {
name = src.name;
format = src.format;
nx = src.nx;
ny = src.ny;
type = src.type;
offset = src.offset;
bitFrom = src.bitFrom;
bitCount = src.bitCount;
size = src.size;
ptr = src.ptr;
name = src.name;
format = src.format;
nx = src.nx;
ny = src.ny;
type = src.type;
offset = src.offset;
bitFrom = src.bitFrom;
bitCount = src.bitCount;
size = src.size;
ptr = src.ptr;
}*/
};
PIVector<Variable> variables;
PIScreenTypes::Alignment alignment;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
};
class PIP_CONSOLE_EXPORT PIScreenConsoleTile : public PIScreenTile
{
class PIP_CONSOLE_EXPORT PIScreenConsoleTile: public PIScreenTile {
public:
PIScreenConsoleTile();
};

View File

@@ -1,23 +1,26 @@
/*! @file piscreendrawer.h
* @brief Drawer for PIScreen
*/
/*! \file piscreendrawer.h
* \ingroup Console
* \~\brief
* \~english Drawer for PIScreen
* \~russian Отрисовщик для PIScreen
*/
/*
PIP - Platform Independent Primitives
Drawer for PIScreen
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Drawer for PIScreen
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 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.
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/>.
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 PISCREENDRAWER_H
@@ -27,10 +30,10 @@
#include "piscreentypes.h"
#include "pistring.h"
class PIP_CONSOLE_EXPORT PIScreenDrawer
{
class PIP_CONSOLE_EXPORT PIScreenDrawer {
friend class PIScreen;
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell> > & c);
PIScreenDrawer(PIVector<PIVector<PIScreenTypes::Cell>> & c);
public:
enum ArtChar {
LineVertical = 1,
@@ -43,26 +46,62 @@ public:
Unchecked,
Checked
};
void clear();
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 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);
PIChar artChar(const ArtChar type) const {return arts_.value(type, PIChar(' '));}
static void clear(PIVector<PIVector<PIScreenTypes::Cell> > & cells);
void clear();
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 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);
PIChar artChar(const ArtChar type) const { return arts_.value(type, PIChar(' ')); }
static void clear(PIVector<PIVector<PIScreenTypes::Cell>> & cells);
private:
PIVector<PIVector<PIScreenTypes::Cell> > & cells;
PIVector<PIVector<PIScreenTypes::Cell>> & cells;
int width, height;
PIMap<ArtChar, PIChar> arts_;
};

View File

@@ -1,59 +1,70 @@
/*! @file piscreentile.h
* @brief Basic PIScreen tile
*/
/*! \file piscreentile.h
* \ingroup Console
* \~\brief
* \~english Basic PIScreen tile
* \~russian Базовый тайл для PIScreen
*/
/*
PIP - Platform Independent Primitives
Basic PIScreen tile
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Basic PIScreen tile
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 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.
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/>.
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 PISCREENTILE_H
#define PISCREENTILE_H
#include "pikbdlistener.h"
#include "pip_console_export.h"
#include "piscreentypes.h"
#include "pikbdlistener.h"
class PIScreenDrawer;
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
friend class PIScreen;
PIOBJECT_SUBCLASS(PIScreenTile, PIObject)
PIOBJECT_SUBCLASS(PIScreenTile, PIObject);
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();
void addTile(PIScreenTile * t);
void takeTile(PIScreenTile * t);
void removeTile(PIScreenTile * t);
PIScreenTile * parentTile() const {return parent;}
PIVector<PIScreenTile * > children(bool only_visible = false);
PIScreenTile * parentTile() const { return parent; }
PIVector<PIScreenTile *> children(bool only_visible = false);
PIScreenTile * childUnderMouse(int x, int y);
void show() {visible = true;}
void hide() {visible = false;}
void show() { visible = true; }
void hide() { visible = false; }
void setFocus();
bool hasFocus() const {return has_focus;}
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;}
bool hasFocus() const { return has_focus; }
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;
}
int x() const { return x_; }
int y() const { return y_; }
int width() const { return width_; }
int height() const { return height_; }
int x() const {return x_;}
int y() const {return y_;}
int width() const {return width_;}
int height() const {return height_;}
PIScreenTypes::Direction direction;
PIScreenTypes::SizePolicy size_policy;
PIScreenTypes::FocusFlags focus_flags;
@@ -64,43 +75,41 @@ public:
int marginLeft, marginRight, marginTop, marginBottom;
int spacing;
bool visible;
protected:
//! Returns desired tile size in "w" and "h"
virtual void sizeHint(int & w, int & h) const;
//! Tile has been resized to "w"x"h"
virtual void resizeEvent(int w, int h) {}
//! Draw tile with drawer "d" in world-space coordinates
virtual void drawEvent(PIScreenDrawer * d) {}
//! Return "true" if you process key
virtual bool keyEvent(PIKbdListener::KeyEvent key) {return false;}
virtual bool keyEvent(PIKbdListener::KeyEvent key) { return false; }
//! Return "true" if you process event
virtual bool mouseEvent(PIKbdListener::MouseEvent me) {return false;}
virtual bool mouseEvent(PIKbdListener::MouseEvent me) { return false; }
//! Return "true" if you process wheel
virtual bool wheelEvent(PIKbdListener::WheelEvent we) {return false;}
virtual bool wheelEvent(PIKbdListener::WheelEvent we) { return false; }
void raiseEvent(PIScreenTypes::TileEvent e);
void setScreen(PIScreenTypes::PIScreenBase * s);
void deleteChildren();
void drawEventInternal(PIScreenDrawer * d);
void layout();
bool needLayout() {return size_policy != PIScreenTypes::Ignore;}
PIVector<PIScreenTile * > tiles;
bool needLayout() { return size_policy != PIScreenTypes::Ignore; }
PIVector<PIScreenTile *> tiles;
PIScreenTile * parent;
PIScreenTypes::PIScreenBase * screen;
int x_, y_, width_, height_;
bool has_focus;
private:
int pw, ph;
};

View File

@@ -1,23 +1,26 @@
/*! @file piscreentiles.h
* @brief Various tiles for PIScreen
*/
/*! \file piscreentiles.h
* \ingroup Console
* \~\brief
* \~english Various tiles for PIScreen
* \~russian Различные тайлы для PIScreen
*/
/*
PIP - Platform Independent Primitives
Various tiles for PIScreen
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Various tiles for PIScreen
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 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.
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/>.
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 PISCREENTILES_H
@@ -28,7 +31,8 @@
class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile {
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile)
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile);
public:
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
TileSimple(const PIString & n = PIString());
@@ -36,39 +40,43 @@ public:
virtual ~TileSimple() {}
PIVector<Row> content;
PIScreenTypes::Alignment alignment;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
};
class TileList;
class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile {
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile)
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile);
friend class TileList;
public:
TileScrollBar(const PIString & n = PIString());
virtual ~TileScrollBar() {}
void setMinimum(int v);
void setMaximum(int v);
void setValue(int v);
int minimum() const {return minimum_;}
int maximum() const {return maximum_;}
int value() const {return value_;}
int minimum() const { return minimum_; }
int maximum() const { return maximum_; }
int value() const { return value_; }
int thickness;
protected:
void _check();
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool mouseEvent(PIKbdListener::MouseEvent me);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
int minimum_, maximum_, value_;
PIChar line_char;
};
class PIP_CONSOLE_EXPORT TileList: public PIScreenTile {
PIOBJECT_SUBCLASS(TileList, PIScreenTile)
PIOBJECT_SUBCLASS(TileList, PIScreenTile);
public:
enum SelectionMode {
NoSelection,
@@ -89,20 +97,22 @@ public:
SelectionMode selection_mode;
PISet<int> selected;
int lhei, cur, offset;
protected:
void sizeHint(int & w, int & h) const;
void resizeEvent(int w, int h);
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
bool wheelEvent(PIKbdListener::WheelEvent we);
void sizeHint(int & w, int & h) const override;
void resizeEvent(int w, int h) override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
bool wheelEvent(PIKbdListener::WheelEvent we) override;
TileScrollBar * scroll;
bool mouse_sel;
};
class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButton, PIScreenTile)
PIOBJECT_SUBCLASS(TileButton, PIScreenTile);
public:
TileButton(const PIString & n = PIString());
virtual ~TileButton() {}
@@ -111,18 +121,18 @@ public:
};
PIScreenTypes::CellFormat format;
PIString text;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
};
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile)
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile);
public:
TileButtons(const PIString & n = PIString());
virtual ~TileButtons() {}
@@ -133,21 +143,23 @@ public:
PIScreenTypes::Alignment alignment;
PIVector<Button> content;
int cur;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
struct Rect {
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0),y0(_y0),x1(_x1),y1(_y1) {}
int x0,y0,x1,y1;
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0), y0(_y0), x1(_x1), y1(_y1) {}
int x0, y0, x1, y1;
};
PIVector<Rect> btn_rects;
};
class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile {
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile)
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile);
public:
TileCheck(const PIString & n = PIString());
virtual ~TileCheck() {}
@@ -157,16 +169,18 @@ public:
PIScreenTypes::CellFormat format;
PIString text;
bool toggled;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
};
class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile {
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile)
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile);
public:
TileProgress(const PIString & n = PIString());
virtual ~TileProgress() {}
@@ -175,37 +189,42 @@ public:
PIString suffix;
double maximum;
double value;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
};
class PIP_CONSOLE_EXPORT TilePICout: public TileList {
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile)
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile);
public:
TilePICout(const PIString & n = PIString());
virtual ~TilePICout() {}
PIScreenTypes::CellFormat format;
int max_lines;
protected:
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
};
class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile {
PIOBJECT_SUBCLASS(TileInput, PIScreenTile)
PIOBJECT_SUBCLASS(TileInput, PIScreenTile);
public:
TileInput(const PIString & n = PIString());
virtual ~TileInput() {}
PIScreenTypes::CellFormat format;
PIString text;
int max_length;
protected:
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
void reserCursor();
int cur, offset;
bool inv;

View File

@@ -1,23 +1,26 @@
/*! @file piscreentypes.h
* @brief Types for PIScreen
*/
/*! \file piscreentypes.h
* \ingroup Console
* \~\brief
* \~english Types for PIScreen
* \~russian Типы для PIScreen
*/
/*
PIP - Platform Independent Primitives
Types for PIScreen
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Types for PIScreen
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 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.
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/>.
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 PISCREENTYPES_H
@@ -30,121 +33,156 @@
class PIScreenTile;
namespace PIScreenTypes {
//! Color for chars or background
enum Color {
Default /** Default */,
Black /** Black */,
Red /** Red */,
Green /** Green */,
Blue /** Blue */,
Cyan /** Cyan */,
Magenta /** Magenta */,
Yellow /** Yellow */,
White /** White */,
Transparent /** Save previous color */
};
//! Flags for chars
enum CharFlag {
Bold /** Bold or bright */ = 0x1,
Blink /** Blink text */ = 0x2,
Underline /** Underline text */ = 0x4,
Inverse = 0x08
};
//! Alignment
enum Alignment {
Left /** Left */ ,
Center /** Center */ ,
Right /** Right */
};
//! Size policy
enum SizePolicy {
Fixed /** Fixed size */ ,
Preferred /** Preferred size */ ,
Expanding /** Maximum available size */ ,
Ignore /** Ignore layout logic */
};
//! Direction
enum Direction {
Horizontal /** Horizontal */ ,
Vertical /** Vertical */
};
//! Focus flags
enum FocusFlag {
CanHasFocus /** Tile can has focus */ = 0x1,
NextByTab /** Focus passed to next tile by tab key */ = 0x2,
NextByArrowsHorizontal /** Focus passed to next tile by arrow keys left or right */ = 0x4,
NextByArrowsVertical /** Focus passed to next tile by arrow keys up or down */ = 0x8,
NextByArrowsAll /** Focus passed to next tile by any arrow key */ = NextByArrowsHorizontal | NextByArrowsVertical,
FocusOnMouse /** Tile focused on mouse press */ = 0x10,
FocusOnWheel /** Tile focused on wheel */ = 0x20,
FocusOnMouseOrWheel /** Tile focused on mouse press or wheel */ = FocusOnMouse | FocusOnWheel
};
typedef PIFlags<CharFlag> CharFlags;
typedef PIFlags<FocusFlag> FocusFlags;
union PIP_CONSOLE_EXPORT CellFormat {
CellFormat(ushort f = 0) {raw_format = f;}
CellFormat(Color col_char, Color col_back = Default, CharFlags flags_ = 0) {
color_char = col_char;
color_back = col_back;
flags = flags_;
}
ushort raw_format;
struct {
ushort color_char : 4;
ushort color_back : 4;
ushort flags : 8;
};
bool operator ==(const CellFormat & c) const {return raw_format == c.raw_format;}
bool operator !=(const CellFormat & c) const {return raw_format != c.raw_format;}
};
struct PIP_CONSOLE_EXPORT Cell {
Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {symbol = c; format = f;}
CellFormat format;
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;}
Cell & operator =(const Cell & c) {
symbol = c.symbol;
if (c.format.color_back == Transparent) {
format.color_char = c.format.color_char;
format.flags = c.format.flags;
} else format = c.format;
return *this;
}
};
//! Color for chars or background
enum Color {
Default /** Default */,
Black /** Black */,
Red /** Red */,
Green /** Green */,
Blue /** Blue */,
Cyan /** Cyan */,
Magenta /** Magenta */,
Yellow /** Yellow */,
White /** White */,
Transparent /** Save previous color */
};
struct PIP_CONSOLE_EXPORT TileEvent {
TileEvent(int t = -1, const PIVariant & d = PIVariant()): type(t), data(d) {}
int type;
PIVariant data;
};
class PIP_CONSOLE_EXPORT PIScreenBase {
public:
PIScreenBase() {}
virtual ~PIScreenBase() {}
virtual void tileEventInternal(PIScreenTile * , TileEvent) {}
virtual void tileRemovedInternal(PIScreenTile * ) {}
virtual void tileSetFocusInternal(PIScreenTile * ) {}
};
//! Flags for chars
enum CharFlag {
Bold /** Bold or bright */ = 0x1,
Blink /** Blink text */ = 0x2,
Underline /** Underline text */ = 0x4,
Inverse = 0x08
};
//! Alignment
enum Alignment {
Left /** Left */,
Center /** Center */,
Right /** Right */
};
//! Size policy
enum SizePolicy {
Fixed /** Fixed size */,
Preferred /** Preferred size */,
Expanding /** Maximum available size */,
Ignore /** Ignore layout logic */
};
//! Direction
enum Direction {
Horizontal /** Horizontal */,
Vertical /** Vertical */
};
//! Focus flags
enum FocusFlag {
CanHasFocus /** Tile can has focus */ = 0x1,
NextByTab /** Focus passed to next tile by tab key */ = 0x2,
NextByArrowsHorizontal /** Focus passed to next tile by arrow keys left or right */ = 0x4,
NextByArrowsVertical /** Focus passed to next tile by arrow keys up or down */ = 0x8,
NextByArrowsAll /** Focus passed to next tile by any arrow key */ = NextByArrowsHorizontal | NextByArrowsVertical,
FocusOnMouse /** Tile focused on mouse press */ = 0x10,
FocusOnWheel /** Tile focused on wheel */ = 0x20,
FocusOnMouseOrWheel /** Tile focused on mouse press or wheel */ = FocusOnMouse | FocusOnWheel
};
typedef PIFlags<CharFlag> CharFlags;
typedef PIFlags<FocusFlag> FocusFlags;
union PIP_CONSOLE_EXPORT CellFormat {
CellFormat(ushort f = 0) { raw_format = f; }
CellFormat(Color col_char, Color col_back = Default, CharFlags flags_ = 0) {
color_char = col_char;
color_back = col_back;
flags = flags_;
}
ushort raw_format;
struct {
ushort color_char: 4;
ushort color_back: 4;
ushort flags : 8;
};
bool operator==(const CellFormat & c) const { return raw_format == c.raw_format; }
bool operator!=(const CellFormat & c) const { return raw_format != c.raw_format; }
};
struct PIP_CONSOLE_EXPORT Cell {
Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {
symbol = c;
format = f;
}
CellFormat format;
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; }
Cell & operator=(const Cell & c) {
symbol = c.symbol;
if (c.format.color_back == Transparent) {
format.color_char = c.format.color_char;
format.flags = c.format.flags;
} else
format = c.format;
return *this;
}
};
struct PIP_CONSOLE_EXPORT TileEvent {
TileEvent(int t = -1, const PIVariant & d = PIVariant()): type(t), data(d) {}
int type;
PIVariant data;
};
class PIP_CONSOLE_EXPORT PIScreenBase {
public:
PIScreenBase() {}
virtual ~PIScreenBase() {}
virtual void tileEventInternal(PIScreenTile *, TileEvent) {}
virtual void tileRemovedInternal(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, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIScreenTypes::Cell) {
s << v.format.raw_format << v.symbol;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIScreenTypes::Cell) {
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;}
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIScreenTypes::TileEvent) {
s << v.type << v.data;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIScreenTypes::TileEvent) {
s >> v.type >> v.data;
return s;
}
inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::TileEvent & v) {s << v.type << v.data; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::TileEvent & v) {s >> v.type >> v.data; return s;}
REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent)

View File

@@ -1,61 +1,64 @@
/*! @file piterminal.h
* @brief Virtual terminal
*/
/*! \file piterminal.h
* \ingroup Console
* \~\brief
* \~english Virtual terminal
* \~russian Виртуальный терминал
*/
/*
PIP - Platform Independent Primitives
Virtual terminal
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Virtual terminal
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 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.
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/>.
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 PITERMINAL_H
#define PITERMINAL_H
#include "pip_console_export.h"
#include "pikbdlistener.h"
#include "pip_console_export.h"
#include "piscreentypes.h"
class PIP_CONSOLE_EXPORT PITerminal: public PIThread
{
PIOBJECT_SUBCLASS(PITerminal, PIThread)
class PIP_CONSOLE_EXPORT PITerminal: public PIThread {
PIOBJECT_SUBCLASS(PITerminal, PIThread);
public:
//! Constructs %PITerminal
PITerminal();
~PITerminal();
int columns() const {return size_x;}
int rows() const {return size_y;}
int columns() const { return size_x; }
int rows() const { return size_y; }
bool resize(int cols, int rows);
void write(const PIByteArray & d);
void write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m);
void write(PIKbdListener::KeyEvent ke);
PIVector<PIVector<PIScreenTypes::Cell> > content();
PIVector<PIVector<PIScreenTypes::Cell>> content();
static bool isSpecialKey(int k);
bool initialize();
void destroy();
private:
void initPrivate();
void readConsole();
void getCursor(int & x, int & y);
uchar invertColor(uchar c);
void run();
void run() override;
#ifndef WINDOWS
void parseInput(const PIString & s);
bool isCompleteEscSeq(const PIString & es);
@@ -69,8 +72,7 @@ private:
int size_x, size_y, cursor_x, cursor_y;
bool cursor_blink, cursor_visible;
PITimeMeasurer cursor_tm;
PIVector<PIVector<PIScreenTypes::Cell> > cells;
PIVector<PIVector<PIScreenTypes::Cell>> cells;
};

View File

@@ -0,0 +1,35 @@
/*
PIP - Platform Independent Primitives
Base macros for generic containers
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 "picontainers.h"
const size_t minAlloc = 64;
size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) {
size_t ret = 0;
size_t elc = 1;
while (elc * szof < minAlloc) {
elc *= 2;
++ret;
}
// printf("calcMinCount sizeof = %d, min_count = %d, pot = %d\n", szof, elc, ret);
return ret;
}

View File

@@ -1,26 +1,34 @@
/*! @file picontainers.h
* @brief Base for generic containers
*
* This file declare all containers and useful macros
* to use them
*/
//! \addtogroup Containers
//! \{
//! \file picontainers.h
//! \brief
//! \~english Base macros for generic containers
//! \~russian Базовые макросы для контейнеров
//! \~\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
Base for generic containers
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Base macros for generic containers
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 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.
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/>.
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 PICONTAINERS_H
@@ -33,91 +41,156 @@
#else
# include <malloc.h>
#endif
#include <algorithm>
#include <functional>
#include <initializer_list>
#include <type_traits>
#include <string.h>
#include <new>
#ifndef PIP_MEMALIGN_BYTES
# define PIP_MEMALIGN_BYTES (sizeof(void*)*4)
#endif
#ifdef WINDOWS
# ifdef CC_GCC
# define amalloc(s) __mingw_aligned_malloc(s, PIP_MEMALIGN_BYTES)
# define afree(p) __mingw_aligned_free(p)
# else
# ifdef CC_VC
# define amalloc(s) _aligned_malloc(s, PIP_MEMALIGN_BYTES)
# define afree(p) _aligned_free(p)
# endif
# endif
#else
# define amalloc(s) aligned_alloc(PIP_MEMALIGN_BYTES, s)
# define afree(p) free(p)
#endif
#include <string.h>
#include <type_traits>
#ifdef DOXYGEN
template<typename C>
class _PIReverseWrapper {
public:
_PIReverseWrapper(C & c): c_(c) {}
_PIReverseWrapper(const C & c): c_(const_cast<C &>(c)) {}
typename C::reverse_iterator begin() { return c_.rbegin(); }
typename C::reverse_iterator end() { return c_.rend(); }
typename C::const_reverse_iterator begin() const { return c_.rbegin(); }
typename C::const_reverse_iterator end() const { return c_.rend(); }
/*!@brief Macro for iterate any container
* \details Use this macros instead of standard "for"
* to get read/write access to each element of container.
* Pass direction is direct \n
* Example: \snippet picontainers.cpp foreach
*/
# define piForeach(i,c)
/*!@brief Macro for iterate any container only for read
* \details Use this macros instead of standard "for"
* to get read access to each element of container.
* Pass direction is direct \n
* Example: \snippet picontainers.cpp foreachC
*/
# define piForeachC(i,c)
/*!@brief Macro for iterate any container with reverse direction
* \details Use this macros instead of standard "for"
* to get read/write access to each element of container.
* Pass direction is reverse \n
* Example: \snippet picontainers.cpp foreachR
*/
# define piForeachR(i,c)
/*!@brief Macro for iterate any container only for read with reverse direction
* \details Use this macros instead of standard "for"
* to get read access to each element of container.
* Pass direction is reverse \n
* Example: \snippet picontainers.cpp foreachCR
*/
# define piForeachCR(i,c)
#else
template <typename C>
struct _reverse_wrapper {
private:
C & c_;
_reverse_wrapper(C & c): c_(c) {}
_reverse_wrapper(const C & c): c_(const_cast<C&>(c)) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
typename C::const_reverse_iterator begin() const {return c_.rbegin();}
typename C::const_reverse_iterator end() const {return c_.rend(); }
};
template <typename C> _reverse_wrapper<C> _reverse_wrap(C & c) {return _reverse_wrapper<C>(c);}
template <typename C> _reverse_wrapper<C> _reverse_wrap(const C & c) {return _reverse_wrapper<C>(c);}
class PIP_EXPORT _PIContainerConstantsBase {
public:
static size_t calcMinCountPoT(size_t szof);
};
template<typename T>
class _PIContainerConstants {
public:
static size_t minCountPoT() {
static const size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T));
return ret;
}
};
# define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)
//! \brief
//! \~english Template reverse wrapper over any container
//! \~russian Шаблонная функция обертки любого контейнера для обратного доступа через итераторы
template<typename C>
_PIReverseWrapper<C> PIReverseWrap(C & c) {
return _PIReverseWrapper<C>(c);
}
template<typename C>
_PIReverseWrapper<C> PIReverseWrap(const C & c) {
return _PIReverseWrapper<C>(c);
}
# define piForeach(i,c) for(i : c)
# define piForeachC(i,c) for(const i : c)
# define piForeachR(i,c) for(i : _reverse_wrap(c))
# define piForeachRC(i,c) for(const i : _reverse_wrap(c))
# define piForeachCR piForeachRC
//! \brief
//! \~english Macro for short replacement of standart "for"
//! \~russian Макрос для короткой записи стандартного цикла "for"
//! \~\param c
//! \~english Iteration times in loop
//! \~russian Количество итераций цикла
#define piForTimes(c) for (int _i##c = 0; _i##c < c; ++_i##c)
#endif // DOXYGEN
//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read/write access to each element of container.
//! Iterating in forward direction.
//! Example of using:
//! \~russian Перебор всех элементов контейнера с доступом на чтение и запись.
//! Перебор осуществляется в прямом порядке.
//! Пример использования:
//! \~\code
//! PIVector<int> vec;
//! vec << 1 << 2 << 3;
//! piForeach(int & i, vec) piCout << i;
//! // 1
//! // 2
//! // 3
//! piForeach(int & i, vec) i++;
//! piForeach(int & i, vec) piCout << i;
//! // 2
//! // 3
//! // 4
//! \endcode
//! \sa \a piForeachC, \a piForeachR, \a piForeachRC
#define piForeach(i, c) for (i: c)
//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read only access to each element of container.
//! Iterating in forward direction.
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
//! Перебор осуществляется в прямом порядке.
//! \~ \sa \a piForeach, \a piForeachR, \a piForeachRC
#define piForeachC(i, c) for (const i: c)
//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read/write access to each element of container.
//! Iterating in backward direction.
//! \~russian Перебор всех элементов контейнера с доступом на чтение и запись.
//! Перебор осуществляется в обратном порядке.
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachRC
#define piForeachR(i, c) for (i: PIReverseWrap(c))
//! \brief
//! \~english Macro for iterate any container
//! \~russian Макрос для перебора любых контейнеров
//! \~\deprecated
//! \~english Deprecated, using only for backward compatibility. Use
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
//! \~russian Устарело, используется только для обратной совместимости. Используйте
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
//! \~\details
//! \~english Get read only access to each element of container.
//! Iterating in backward direction. Also has alias **piForeachCR**
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
//! Перебор осуществляется в обратном порядке. Также можно писать **piForeachCR**
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachR
#define piForeachRC(i, c) for (const i: PIReverseWrap(c))
#define piForeachCR piForeachRC
//! \~\brief
//! \~english Reshape order enum for reshape() function.
//! \~russian Порядок обхода для функции изменения размерности reshape().
//! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape()
enum ReshapeOrder {
ReshapeByRow /*! \~english Traversing elements by line, just as they stay in memory \~russian Обход элементов построчно, так же как они
находятся в памяти */
,
ReshapeByColumn /*! \~english Traversing elements by column \~russian Обход элементов по столбцам */,
};
#endif // PICONTAINERS_H

View File

@@ -1,31 +1,192 @@
/*
PIP - Platform Independent Primitives
Module includes
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Containers
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 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.
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/>.
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 Containers Containers
//! \~\brief
//! \~english Various standart containers realization
//! \~russian Различные классы контейнеров
//!
//! \~\details
//! \~english \section cmake_module_Containers Building with CMake
//! \~russian \section cmake_module_Containers Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP)
//! \endcode
//!
//! \~english \section containers_module_list Content
//! \~russian \section containers_module_list Состав
//!
//! \~english
//! Class | Description
//! ------------- | -----------
//! \a PIVector | Linear array, fast back insert
//! \a PIDeque | Linear array, fast back and front insert
//! \a PIMap | Dictionary container, key/value array
//! \a PISet | Set container
//! \a PIStack | Stack
//! \a PIQueue | Queue
//! \a PIPair | Pair
//! \a PIVector2D | Linear 2D rectangle array
//!
//! \~russian
//! Класс | Описание
//! ------------- | -----------
//! \a PIVector | Линейный массив, быстрое добавление в конец
//! \a PIDeque | Линейный массив, быстрое добавление вначало и конец
//! \a PIMap | Массив ключ/значение, словарь
//! \a PISet | Множество
//! \a PIStack | Стек
//! \a PIQueue | Очередь
//! \a PIPair | Пара
//! \a PIVector2D | Линейный двумерный прямоугольный массив
//!
//!
//! \~english \section stl_iterators STL-Style Iterators
//! \~russian \section stl_iterators Итераторы в стиле STL
//! \~english
//! \brief They are compatible with Qt's and STL's generic algorithms and are optimized for speed.
//! \details
//! For each container class, there are two STL-style iterator types:
//! one that provides read-only access and one that provides read-write access.
//! Read-only iterators should be used wherever possible
//! because they are faster than read-write iterators.
//! Read-only iterator - `const_iterator.`
//! Read-write iterator - `iterator.`
//!
//! The API of the STL iterators is modelled on pointers in an array.
//! For example, the `++` operator advances the iterator to the next item,
//! and the `*` operator returns the item that the iterator points to.
//! The `iterator` type is just a `typedef` for `T *`,
//! and the `const_iterator` type is just a `typedef` for `const T *`.
//! STL-style iterators point directly at items.
//! The `begin()` function of a container
//! returns an iterator that points to the first item in the container.
//! The `end()` function of a container returns an iterator to the imaginary item
//! one position past the last item in the container.
//! `end()` marks an invalid position; it must never be dereferenced.
//! It is typically used in a loop's break condition.
//!
//! Example:
//! \code
//! for (PIVector<int>::const_iterator i = v.begin(); i != v.end(); ++i) piCout << *i;
//! std::for_each(v.begin(), v.end(), [](int n){std::cout << n << ' ';});
//! \endcode
//!
//! If the list is empty, `begin()` equals `end()`, so we never execute the loop.
//!
//! ![iterators](doc/images/pivector_rbegin.png)
//!
//! The following table summarizes the STL-style iterators' API:
//! Expression | Behavior
//! ---------- | --------------------
//! `*i` | Returns the current item
//! `++i` | Advances the iterator to the next item
//! `i += n` | Advances the iterator by `n` items
//! `--i` | Moves the iterator back by one item
//! `i -= n` | Moves the iterator back by `n` items
//! `i - j` | Returns the number of items between iterators `i` and `j`
//!
//! The `++` and `--` operators are available both as prefix `(++i, --i)`
//! and postfix `(i++, i--)` operators.
//! The prefix versions modify the iterators
//! and return a reference to the modified iterator;
//! the postfix versions take a copy of the iterator before they modify it, and return that copy.
//! In expressions where the return value is ignored,
//! we recommend that you use the prefix operators `(++i, --i)`, as these are slightly faster.
//! For non-const iterator types, the return value of the unary `*` operator
//! can be used on the left side of the assignment operator.
//!
//! \~russian
//! \brief Они совместимы с базовыми алгоритмами Qt и STL и оптимизированы по скорости.
//! \details
//! Для каждого контейнерного класса есть два типа итераторов в стиле STL:
//! один из них предоставляет доступ только для чтения, а другой - доступ для чтения-записи.
//! Итераторы только для чтения должны использоваться везде, где это только возможно,
//! так как они быстрее, чем итераторы для чтения-записи.
//! Итератор только для чтения - `const_iterator.`
//! Итератор для чтения-записи - `iterator.`
//!
//! API итераторов в стиле STL сделан по образцу указателей в массиве.
//! Например, оператор `++` перемещает итератор к следующему элементу,
//! а оператор `*` возвращает элемент, на который позиционирован итератор.
//! Тип `iterator` - это как `typedef` для `T *`,
//! а тип `const_iterator` - как `typedef` для `const T *`.
//! Итераторы в стиле STL указывают непосредственно на элемент.
//! Функция контейнера `begin()` возвращает итератор, указывающий на первый элемент контейнера.
//! Функция контейнера `end()` возвращает итератор, указывающий на воображаемый элемент,
//! находящийся в позиции, следующей за последним элементом контейнера.
//! `end()` обозначает несуществующую позицию;
//! он никогда не должен разыменовываться.
//! Обычно, он используется, как условие выхода из цикла.
//!
//! Например:
//! \code
//! for (PIVector<int>::const_iterator i = v.begin(); i != v.end(); ++i) piCout << *i;
//! std::for_each(v.begin(), v.end(), [](int n){std::cout << n << ' ';});
//! \endcode
//!
//! Если список пуст, то begin() равен end(), поэтому цикл никогда не выполнится.
//!
//! ![итераторы](doc/images/pivector_rbegin.png)
//!
//! В следующей таблице подводится итог API итераторов в стиле STL:
//! Выражение | Поведение
//! --------- | --------------------
//! `*i` | Возвращает текущий элемент
//! `++i` | Перемещает итератор к следующему элементу
//! `i += n` | Перемещает итератор вперед на `n` элементов
//! `--i` | Перемещает итератор на один элемент назад
//! `i -= n` | Перемещает итератор назад на `n` элементов
//! `i - j` | Возвращает количество элементов, находящихся между итераторами `i` и `j`
//!
//! Оба оператора `++` и `--` могут использоваться и как префиксные `(++i, --i)`
//! и как постфиксные `(i++, i--)` операторы.
//! Префиксная версия изменяет итератор, и возвращает ссылку на измененный итератор;
//! постфиксная версия, берет копию итератора перед его изменением, и возвращает эту копию.
//! В выражениях, в которых возвращаемое значение игнорируется,
//! мы рекомендуем использовать префиксную версию `(++i, --i)`,
//! так как она несколько быстрее.
//!
//! Для неконстантных итераторов, возвращаемое значение унарного оператора `*`
//! может быть использовано с левой стороны от оператора присваивания.
//!
//!
//! \authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
#ifndef PICONTAINERSMODULE_H
#define PICONTAINERSMODULE_H
#include "pivector.h"
#include "pideque.h"
#include "pimap.h"
#include "piqueue.h"
#include "piset.h"
#include "pistack.h"
#include "pivector.h"
#include "pivector2d.h"
#endif // PICONTAINERSMODULE_H

View File

@@ -1,25 +1,34 @@
/*! @file pideque.h
* @brief Dynamic array of any type
*
* This file declares PIDeque
*/
//! \addtogroup Containers
//! \{
//! \file pideque.h
//! \brief
//! \~english Declares \a PIDeque
//! \~russian Объявление \a PIDeque
//! \~\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
Dynamic array of any type
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Dynamic array of any type
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 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.
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/>.
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 PIDEQUE_H
@@ -28,679 +37,2748 @@
#include "picontainers.h"
template <typename T>
//! \addtogroup Containers
//! \{
//! \class PIDeque
//! \brief
//! \~english Sequence two-way linear container - dynamic size array of any type.
//! \~russian Последовательный двухсторонний контейнер с линейной памятью - динамический массив любого типа.
//! \~\}
//! \details
//! \~english
//! The elements are stored contiguously,
//! which means that elements can be accessed not only through iterators,
//! but also using offsets to regular pointers to elements.
//! This means that a pointer to an element of a PIDeque may be passed to any function
//! that expects a pointer to an element of an array.
//! To add elements you can use functions \a append() and \a insert(),
//! to remove elements you can use functions \a remove() and \a removeOne(), \a removeWhere().
//! Change size by function \a resize() and \a assign().
//! Items in an array are numbered, starting from zero.
//! This number is called the item's index.
//! So the first item has index 0, the last has index `size() - 1`.
//! A set of various convenient functions is also available for the array,
//! for example: \a indexOf(), \a contains(), \a entries(), \a isEmpty(), \a isNotEmpty(),
//! \a every(), \a any(), \a forEach(), \a indexWhere(), \a getRange(), \a sort(),
//! \a map(), \a reduce(), \a filter(), \a flatten(), \a reshape() and others.
//!
//! The storage of the PIDeque is handled automatically,
//! being expanded as needed.
//! PIDeque usually occupy more space than \a PIVector,
//! because more memory is allocated to handle future growth
//! from both the beginning and the end.
//! This way a PIDeque does not need to reallocate each time an element is inserted,
//! but only when the additional memory is exhausted.
//! The total amount of allocated memory can be queried using \a capacity() function.
//! Reallocations are usually costly operations in terms of performance.
//! The \a reserve() function can be used to eliminate reallocations
//! if the number of elements is known beforehand.
//!
//! The complexity (efficiency) of common operations on PIDeque is as follows:
//! - Random access - constant O(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 O(n)
//!
//! \~russian
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
//! но и с помощью смещений для обычных указателей на элементы.
//! Это означает, что указатель на элемент PIDeque может передаваться в любую функцию,
//! ожидающую указатель на элемент массива.
//! Добавить элементы можно с помощью функции \a append() или \a insert(),
//! а удалить с помощью \a remove() или \a removeOne(), \a removeWhere().
//! Изменить размер можно функцией \a resize() или \a assign().
//! Массив индексируется с нуля:
//! первый элемент массива имеет индекс, равный `0`,
//! а индекс последнего элемента равен `size() - 1`.
//! Также для массива доступен набор различных удобных функций,
//! например: \a indexOf(), \a contains(), \a entries(), \a isEmpty(), \a isNotEmpty(),
//! \a every(), \a any(), \a forEach(), \a indexWhere(), \a getRange(), \a sort(),
//! \a map(), \a reduce(), \a filter(), \a flatten(), \a reshape() и другие.
//!
//! Память PIDeque обрабатывается автоматически,
//! расширяясь по мере необходимости.
//! PIDeque занимает больше места, чем \a PIVector, поскольку
//! больше памяти выделяется для обработки будущего роста и с начала и с конца.
//! Таким образом, память для PIDeque требуется выделять
//! не при каждой вставке элемента, а только после исчерпания дополнительной памяти.
//! Общий объём выделенной памяти можно получить с помощью функции \a capacity().
//!
//! Выделение памяти обычно является дорогостоящей операцией
//! с точки зрения производительности.
//! Функцию \a reserve() можно использовать для исключения выделения памяти,
//! если количество элементов известно заранее.
//!
//! Сложность (эффективность) обычных операций над PIDeque следующая:
//! - Произвольный доступ — постоянная O(1)
//! - Вставка и удаление элементов в конце или начале — амортизированная постоянная O(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n)
//!
//! \~\sa \a PIVector, \a PIMap
template<typename T>
class PIDeque {
public:
inline PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
typedef bool (*CompareFunc)(const T &, const T &);
typedef T value_type;
typedef T * pointer;
typedef const T * const_pointer;
typedef T & reference;
typedef const T & const_reference;
typedef size_t size_type;
//! \~english Constructs an empty array.
//! \~russian Создает пустой массив.
inline PIDeque() { PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) }
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIDeque(const PIDeque<T> & other) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
inline PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(other.pid_size, true);
alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
}
inline PIDeque(std::initializer_list<T> init_list): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
//! \~english Contructs array from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Создает массив из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\details
//! \~\code
//! PIDeque <int> v{1,2,3};
//! piCout << v; // {1, 2, 3}
//! \endcode
inline PIDeque(std::initializer_list<T> init_list) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(init_list.size(), true);
alloc_forward(init_list.size());
newT(pid_data, init_list.begin(), init_list.size());
}
inline PIDeque(const T * data, size_t size): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
//! \~english Contructs array from raw `data`.
//! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`.
inline PIDeque(const T * data, size_t size) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(size, true);
alloc_forward(size);
newT(pid_data + pid_start, data, pid_size);
}
inline PIDeque(size_t pid_size, const T & f = T()): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
//! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `e`.
inline explicit PIDeque(size_t pid_size, const T & e = T()) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, f);
expand(pid_size, e);
}
inline PIDeque(size_t piv_size, std::function<T(size_t)> f): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
//! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
//! \~russian Создает массив из `size` элементов созданных функцией `f(size_t i)`.
//! \~\details
//! \~english Can use
//! [Lambda expressions](https://en.cppreference.com/w/cpp/language/lambda)
//! as constructor argument.
//! \~russian Позволяет передавать
//! [Лямбда-выражения](https://ru.cppreference.com/w/cpp/language/lambda)
//! для создания элементов в конструкторе.
//! \~\code
//! PIDeque <int> v(5, [](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4, 6, 8}
//! \endcode
inline PIDeque(size_t piv_size, std::function<T(size_t i)> f) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
expand(piv_size, f);
}
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) {
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIDeque(PIDeque<T> && other) {
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();
}
inline virtual ~PIDeque() {
inline ~PIDeque() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
deleteT(pid_data + pid_start, pid_size);
dealloc();
_reset();
}
inline PIDeque<T> & operator =(const PIDeque<T> & other) {
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIDeque<T> & operator=(const PIDeque<T> & other) {
if (this == &other) return *this;
deleteT(pid_data + pid_start, pid_size);
alloc(other.pid_size, true);
clear();
alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
return *this;
}
inline PIDeque<T> & operator =(PIDeque<T> && other) {
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIDeque<T> & operator=(PIDeque<T> && other) {
swap(other);
return *this;
}
typedef T value_type;
enum ReshapeOrder {
byRow,
byColumn
};
class iterator {
friend class PIDeque<T>;
private:
inline iterator(PIDeque<T> * v, size_t p): parent(v), pos(p) {}
inline iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent;
size_t pos;
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 iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {++pos;}
inline void operator ++(int) {++pos;}
inline void operator --() {--pos;}
inline void operator --(int) {--pos;}
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
inline T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline iterator & operator++() {
++pos;
return *this;
}
inline iterator operator++(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline iterator & operator--() {
--pos;
return *this;
}
inline iterator operator--(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline iterator & operator+=(const iterator & it) {
pos += it.pos;
return *this;
}
inline iterator & operator+=(size_t p) {
pos += p;
return *this;
}
inline iterator & operator-=(const iterator & it) {
pos -= it.pos;
return *this;
}
inline iterator & operator-=(size_t p) {
pos -= p;
return *this;
}
friend inline iterator operator-(size_t p, const iterator & it) { return it - p; }
friend inline iterator operator-(const iterator & it, size_t p) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const iterator & it1, const iterator & it2) { return it1.pos - it2.pos; }
friend inline iterator operator+(size_t p, const iterator & it) { return it + p; }
friend inline iterator operator+(const iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
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) { 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) { return it1.pos >= it2.pos; }
};
class const_iterator {
friend class PIDeque<T>;
private:
inline const_iterator(const PIDeque<T> * v, size_t p): parent(v), pos(p) {}
inline const_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent;
size_t pos;
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)[pos];}
inline void operator ++() {++pos;}
inline void operator ++(int) {++pos;}
inline void operator --() {--pos;}
inline void operator --(int) {--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 const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
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; }
};
class reverse_iterator {
friend class PIDeque<T>;
private:
inline reverse_iterator(PIDeque<T> * v, size_t p): parent(v), pos(p) {}
inline reverse_iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent;
size_t pos;
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 reverse_iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;}
inline void operator ++(int) {--pos;}
inline void operator --() {++pos;}
inline void operator --(int) {++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 T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline reverse_iterator & operator++() {
--pos;
return *this;
}
inline reverse_iterator operator++(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline reverse_iterator & operator--() {
++pos;
return *this;
}
inline reverse_iterator operator--(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline reverse_iterator & operator+=(const reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline reverse_iterator & operator+=(size_t p) {
pos -= p;
return *this;
}
inline reverse_iterator & operator-=(const reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline reverse_iterator & operator-=(size_t p) {
pos += p;
return *this;
}
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) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const reverse_iterator & it1, const reverse_iterator & it2) { 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+(const reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
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) { 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) { return it1.pos >= it2.pos; }
};
class const_reverse_iterator {
friend class PIDeque<T>;
private:
inline const_reverse_iterator(const PIDeque<T> * v, size_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;
size_t pos;
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_reverse_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;}
inline void operator ++(int) {--pos;}
inline void operator --() {++pos;}
inline void operator --(int) {++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 const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline const_reverse_iterator & operator++() {
--pos;
return *this;
}
inline const_reverse_iterator operator++(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline const_reverse_iterator & operator--() {
++pos;
return *this;
}
inline const_reverse_iterator operator--(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline const_reverse_iterator & operator+=(const const_reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_reverse_iterator & operator+=(size_t p) {
pos -= p;
return *this;
}
inline const_reverse_iterator & operator-=(const const_reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline const_reverse_iterator & operator-=(size_t p) {
pos += p;
return *this;
}
friend inline const_reverse_iterator operator-(size_t p, const const_reverse_iterator & it) { return it - p; }
friend inline const_reverse_iterator operator-(const const_reverse_iterator & it, size_t p) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
return it2.pos - it1.pos;
}
friend inline const_reverse_iterator operator+(size_t p, const const_reverse_iterator & it) { return it + p; }
friend inline const_reverse_iterator operator+(const const_reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
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) { 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) { return it1.pos >= it2.pos; }
};
inline iterator begin() {return iterator(this, 0);}
inline iterator end() {return iterator(this, pid_size);}
inline const_iterator begin() const {return const_iterator(this, 0);}
inline const_iterator end() const {return const_iterator(this, pid_size);}
inline reverse_iterator rbegin() {return reverse_iterator(this, pid_size - 1);}
inline reverse_iterator rend() {return reverse_iterator(this, -1);}
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, pid_size - 1);}
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
inline size_t size() const {return pid_size;}
inline ssize_t size_s() const {return pid_size;}
inline size_t length() const {return pid_size;}
inline size_t capacity() const {return pid_rsize;}
inline size_t _start() const {return pid_start;}
inline bool isEmpty() const {return (pid_size == 0);}
//! \~english Iterator to the first element.
//! \~russian Итератор на первый элемент.
//! \~\details ![begin, end](doc/images/pivector_begin.png)
//!
//! \~english If the array is empty, the returned iterator is equal to \a end().
//! \~russian Если массив - пуст, возвращаемый итератор будет равен \a end().
//! \~\return \ref stl_iterators
//! \~\sa \a end(), \a rbegin(), \a rend()
inline iterator begin() { return iterator(this, 0); }
inline T & operator [](size_t index) {return pid_data[pid_start + index];}
inline const T & operator [](size_t index) const {return pid_data[pid_start + index];}
inline const T & at(size_t index) const {return pid_data[pid_start + index];}
inline T & back() {return pid_data[pid_start + pid_size - 1];}
inline const T & back() const {return pid_data[pid_start + pid_size - 1];}
inline T & front() {return pid_data[pid_start];}
inline const T & front() const {return pid_data[pid_start];}
inline bool operator ==(const PIDeque<T> & t) const {
if (pid_size != t.pid_size) return false;
for (size_t i = 0; i < pid_size; ++i)
if (t[i] != (*this)[i])
return false;
//! \~english Iterator to the element following the last element.
//! \~russian Итератор на элемент, следующий за последним элементом.
//! \~\details ![begin, end](doc/images/pivector_begin.png)
//!
//! \~english This element acts as a placeholder;
//! attempting to access it results in undefined behavior.
//! \~russian Этот элемент существует лишь условно,
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\return \ref stl_iterators
//! \~\sa \a begin(), \a rbegin(), \a rend()
inline iterator end() { return iterator(this, pid_size); }
inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, pid_size); }
//! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
//! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png)
//!
//! \~english It corresponds to the last element of the non-reversed array.
//! If the array is empty, the returned iterator is equal to \a rend().
//! \~russian Итератор для прохода массива в обратном порядке.
//! Указывает на последний элемент.
//! Если массив пустой, то совпадает с итератором \a rend().
//! \~\return \ref stl_iterators
//! \~\sa \a rend(), \a begin(), \a end()
inline reverse_iterator rbegin() { return reverse_iterator(this, pid_size - 1); }
//! \~english Returns a reverse iterator to the element.
//! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент,
//! следующий за последним элементом.
//! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png)
//!
//! \~english It corresponds to the element preceding the first element of the non-reversed array.
//! This element acts as a placeholder, attempting to access it results in undefined behavior.
//! \~russian Итератор для прохода массива в обратном порядке.
//! Указывает на элемент, предшествующий первому элементу.
//! Этот элемент существует лишь условно,
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\return \ref stl_iterators
//! \~\sa \a rbegin(), \a begin(), \a end()
inline reverse_iterator rend() { return reverse_iterator(this, -1); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(this, pid_size - 1); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(this, -1); }
//! \~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 pid_size; }
//! \~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 ssize_t size_s() const { return pid_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 pid_size; }
//! \~english Number of elements that the container has currently allocated space for.
//! \~russian Количество элементов, для которого сейчас выделена память массивом.
//! \~\details
//! \~english To find out the actual number of items, use the function \a size().
//! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size().
//! \~\sa \a reserve(), \a size(), \a size_s()
inline size_t capacity() const { return pid_rsize; }
inline size_t _start() const { return pid_start; }
//! \~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 (pid_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 (pid_size > 0); }
//! \~english Tests whether at least one element in the array
//! passes the test implemented by the provided function `test`.
//! \~russian Проверяет, удовлетворяет ли какой-либо элемент массива условию,
//! заданному в передаваемой функции `test`.
//! \~\return
//! \~english **true** if, in the array,
//! it finds an element for which the provided function returns **true**;
//! otherwise it returns **false**. Always returns **false** if is empty.
//! \~russian **true** если хотя бы для одного элемента
//! передаваемая функция возвращает **true**, в остальных случаях **false**.
//! Метод возвращает **false** при любом условии для пустого массива.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 8, 9};
//! piCout << v.any([](int e){return e % 2 == 0;}); // true
//! piCout << v.any([](int e){return e == 3;}); // false
//! \endcode
//! \~\sa \a every(), \a contains(), \a entries(), \a forEach()
inline bool any(std::function<bool(const T & e)> test) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
if (test(pid_data[i])) return true;
}
return false;
}
//! \~english Tests whether all elements in the array passes the test
//! implemented by the provided function `test`.
//! \~russian Проверяет, удовлетворяют ли все элементы массива условию,
//! заданному в передаваемой функции `test`.
//! \~\return
//! \~english **true** if, in the array,
//! it finds an element for which the provided function returns **true**;
//! otherwise it returns **false**. Always returns **true** if is empty.
//! \~russian **true** если для всех элементов передаваемая функция возвращает **true**,
//! в остальных случаях **false**.
//! Метод возвращает **true** при любом условии для пустого массива.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 8, 9};
//! piCout << v.every([](int e){return e % 2 == 0;}); // false
//! piCout << v.every([](int e){return e > 0;}); // true
//! \endcode
//! \~\sa \a any(), \a contains(), \a entries(), \a forEach()
inline bool every(std::function<bool(const T & e)> test) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
if (!test(pid_data[i])) return false;
}
return true;
}
inline bool operator !=(const PIDeque<T> & t) const {return !(*this == t);}
inline bool operator >(const PIDeque<T> & t) const {
if (pid_size != t.pid_size) return pid_size > t.pid_size;
for (size_t i = 0; i < pid_size; ++i)
if (t[i] != (*this)[i]) return t[i] > (*this)[i];
//! \~english Full access to element by `index`.
//! \~russian Полный доступ к элементу по индексу `index`.
//! \~\details
//! \~english Element index starts from `0`.
//! Element index must be in range from `0` to `size()-1`.
//! Otherwise will be undefined behavior.
//! \~russian Индекс элемента считается от `0`.
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! \~\code
//! PIDeque<int> v{1, 2, 8, 9};
//! piCout << v[2]; // 8
//! v[2] = 5;
//! piCout << v; // {1, 2, 5, 9}
//! \endcode
//! \~\sa \a at()
inline T & operator[](size_t index) { return pid_data[pid_start + index]; }
inline const T & operator[](size_t index) const { return pid_data[pid_start + index]; }
//! \~english Read only access to element by `index`.
//! \~russian Доступ исключительно на чтение к элементу по индексу `index`.
//! \~\details
//! \~english Element index starts from `0`.
//! Element index must be in range from `0` to `size()-1`.
//! Otherwise will be undefined behavior.
//! \~russian Индекс элемента считается от `0`.
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
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.
//! \~russian Последний элемент массива.
//! \~\details
//! \~english Returns a reference to the last item in the array.
//! This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Возвращает ссылку на последний элемент в массиве.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline T & back() { return pid_data[pid_start + pid_size - 1]; }
inline const T & back() const { return pid_data[pid_start + pid_size - 1]; }
//! \~english Last element.
//! \~russian Первый элемент массива.
//! \~\details
//! \~english Returns a reference to the last item in the array.
//! This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Возвращает ссылку на пенрвый элемент в массиве.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline T & front() { return pid_data[pid_start]; }
inline const T & front() const { return pid_data[pid_start]; }
//! \~english Compare operator with array `v`.
//! \~russian Оператор сравнения с массивом `v`.
inline bool operator==(const PIDeque<T> & v) const {
if (pid_size != v.pid_size) return false;
for (size_t i = 0; i < pid_size; ++i) {
if (v[i] != (*this)[i]) return false;
}
return true;
}
//! \~english Compare operator with array `v`.
//! \~russian Оператор сравнения с массивом `v`.
inline bool operator!=(const PIDeque<T> & v) const { return !(*this == v); }
//! \~english Tests if element `e` exists in the array.
//! \~russian Проверяет наличие элемента `e` в массиве.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! **false** is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4};
//! piCout << v.contains(3); // true
//! piCout << v.contains(5); // false
//! piCout << v.contains(3, 3); // false
//! piCout << v.contains(3, -2); // true
//! piCout << v.contains(3, -99); // true
//! \endcode
//! \~\return
//! \~english **true** if the array contains an occurrence of element `e`,
//! otherwise it returns **false**.
//! \~russian **true** если элемент `e` присутствует в массиве,
//! в остальных случаях **false**.
//! \~\sa \a every(), \a any(), \a entries(), \a forEach()
inline bool contains(const T & e, ssize_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
if (e == pid_data[i]) return true;
}
return false;
}
inline bool contains(const T & v) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
if (v == pid_data[i])
return true;
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;
}
inline int etries(const T & v) const {
//! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! 0 is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<int> v{2, 2, 4, 2, 6};
//! piCout << v.entries(2); // 3
//! piCout << v.entries(2, 2); // 1
//! piCout << v.entries(2, -4); // 2
//! \endcode
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexOf()
inline int entries(const T & e, ssize_t start = 0) const {
int ec = 0;
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
if (v == pid_data[i]) ++ec;
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
if (e == pid_data[i]) ++ec;
}
return ec;
}
inline ssize_t indexOf(const T & v) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i)
if (v == pid_data[i])
return i - pid_start;
return -1;
//! \~english Count elements in the array passes the test implemented by the provided function `test`.
//! \~russian Подсчитывает количество элементов в массиве,
//! проходящих по условию, заданному в передаваемой функции `test`.
//! \~\details
//! \~english Overloaded function.
//! Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! 0 is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Перегруженная функция.
//! Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\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 {
int ec = 0;
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
if (test(pid_data[i])) ++ec;
}
return ec;
}
inline ssize_t lastIndexOf(const T & v) const {
for (ssize_t i = pid_start + (ssize_t)pid_size - 1; i >= pid_start; --i)
if (v == pid_data[i])
return i - pid_start;
//! \~english Returns the first index at which a given element `e`
//! can be found in the array, or `-1` if it is not present.
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
//! может быть найден в массиве или `-1`, если такого индекса нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! `-1` is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<int> v{2, 5, 9};
//! piCout << v.indexOf(2); // 0
//! piCout << v.indexOf(7); // -1
//! piCout << v.indexOf(9, 2); // 2
//! piCout << v.indexOf(2, -1); // -1
//! piCout << v.indexOf(2, -3); // 0
//! \endcode
//! \~\sa \a indexWhere(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
if (e == pid_data[i]) {
return ssize_t(i) - pid_start;
}
}
return -1;
}
inline T * data(size_t index = 0) {return &(pid_data[pid_start + index]);}
inline const T * data(size_t index = 0) const {return &(pid_data[pid_start + index]);}
//! \~english Returns the first index passes the test implemented by the provided function `test`,
//! or `-1` if it is not present.
//! can be found in the array, or `-1` if it is not present.
//! \~russian Возвращает первый индекс элемента проходящего по условию,
//! заданному в передаваемой функции `test`, или `-1`, если таких элементов нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! `-1` is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<PIString> v{"do", "re", "mi", "re"};
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('r');}); // 1
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('r');}, 2); // 3
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('k');}); // -1
//! \endcode
//! \~\sa \a indexOf(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
if (test(pid_data[i])) {
return ssize_t(i) - pid_start;
}
}
return -1;
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
//! \~english Returns the last index at which a given element `e`
//! can be found in the array, or `-1` if it is not present.
//! \~russian Возвращает последний индекс, по которому данный элемент `e`
//! может быть найден в массиве или `-1`, если такого индекса нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array
//! at which to start searching backwards.
//! If the index is greater than or equal to the array's size,
//! causes the whole array to be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Therefore, if calculated index less than 0,
//! the array is not searched, and the method returns `-1`.
//! Note: if the provided index is negative,
//! the array is still searched from back to front.
//! Default: -1 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
//! \~\code
//! PIDeque<int> v{2, 5, 9, 2};
//! piCout << v.lastIndexOf(2); // 3
//! piCout << v.lastIndexOf(7); // -1
//! piCout << v.lastIndexOf(2, 2); // 0
//! piCout << v.lastIndexOf(2, -3); // 0
//! piCout << v.lastIndexOf(2, -300); // -1
//! piCout << v.lastIndexOf(2, 300); // 3
//! \endcode
//! \~\sa \a indexOf(), \a indexWhere(), \a lastIndexWhere(), \a contains()
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start >= size_s()) start = pid_size - 1;
if (start < 0) start = pid_size + start;
for (ssize_t i = ssize_t(pid_start) + start; i >= ssize_t(pid_start); --i) {
if (e == pid_data[i]) {
return i - ssize_t(pid_start);
}
}
return -1;
}
//! \~english Returns the last index passes the test implemented by the provided function `test`,
//! or `-1` if it is not present.
//! \~russian Возвращает последний индекс элемента проходящего по условию,
//! заданному в передаваемой функции `test`, или `-1`, если таких элементов нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array
//! at which to start searching backwards.
//! If the index is greater than or equal to the array's size,
//! causes the whole array to be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Therefore, if calculated index less than 0,
//! the array is not searched, and the method returns `-1`.
//! Note: if the provided index is negative,
//! the array is still searched from back to front.
//! Default: -1 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
//! \~\sa \a indexOf(), \a lastIndexOf(), \a indexWhere(), \a contains()
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 < 0) start = pid_size + start;
for (ssize_t i = ssize_t(pid_start) + start; i >= ssize_t(pid_start); --i) {
if (test(pid_data[i])) {
return i - ssize_t(pid_start);
}
}
return -1;
}
//! \~english Pointer to array
//! \~russian Указатель на память массива
//! \~\details
//! \~english Optional argument `index` the position in this array,
//! where is pointer. Default: start of array.
//! \~russian Опциональный аргумент `index` указывает на индекс c которого брать указатель.
//! По умолчанию указывает на начало массива.
//! \~\code
//! PIDeque<int> v{2, 5, 9, 2};
//! int a[2] = {12, 13};
//! memcpy(vec.data(1), a, 2 * sizeof(int));
//! piCout << v; // {2, 12, 13, 2}
//! \endcode
inline T * data(size_t index = 0) { return &(pid_data[pid_start + index]); }
//! \~english Read only pointer to array
//! \~russian Указатель на память массива только для чтения.
//! \~\details
//! \~english The pointer can be used to access and modify the items in the array.
//! The pointer remains valid as long as the array isn't reallocated.
//! Optional argument `index` the position in this array,
//! where is pointer. Default: start of array.
//! \~russian Указатель можно использовать для доступа и изменения элементов в массиве.
//! Указатель остается действительным только до тех пор, пока массив не будет перераспределен.
//! Опциональный аргумент `index` указывает на индекс c которого брать указатель.
//! По умолчанию указывает на начало массива.
//! \~\code
//! PIDeque<int> v{1, 3, 5};
//! int a[3];
//! memcpy(a, v.data(), a.size() * sizeof(int));
//! piCout << a[0] << a[1] << a[2]; // 1 3 5
//! \endcode
inline const T * data(size_t index = 0) const { return &(pid_data[pid_start + index]); }
//! \~english Creates 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`).
PIDeque<T> getRange(size_t index, size_t count) const {
if (index >= pid_size || count == 0) return PIDeque<T>();
if (index + count > pid_size) count = pid_size - index;
return PIDeque(pid_data + pid_start + index, count);
}
//! \~english Clear array, remove all elements.
//! \~russian Очищает массив, удаляет все элементы.
//! \~\details
//! \~\note
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
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;
}
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 PIDeque<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size)
pid_size = 0;
pid_size = 0;
pid_start = (pid_rsize - pid_size) / 2;
return *this;
}
inline PIDeque<T> & fill(const T & f = T()) {
//! \~english Assigns element 'e' to all items in the array.
//! \~russian Заполняет весь массив копиями элемента 'e'.
//! \~\details
//! \code
//! PIDeque<int> v{1, 3, 5};
//! v.fill(7);
//! piCout << v; // {7, 7, 7}
//! \endcode
//! \~\sa \a resize()
inline PIDeque<T> & fill(const T & e = T()) {
deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, pid_size)
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
elementNew(pid_data + i, f);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
elementNew(pid_data + i, e);
}
return *this;
}
inline PIDeque<T> & fill(std::function<T(size_t)> f) {
//! \~english Assigns result of function 'f(size_t i)' to all items in the array.
//! \~russian Заполняет весь массив результатом вызова функции 'f(size_t i)'.
//! \~\details
//! \code
//! PIDeque<int> v{1, 3, 5};
//! v.fill([](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4}
//! \endcode
//! \~\sa \a resize()
inline PIDeque<T> & fill(std::function<T(size_t i)> f) {
deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, pid_size)
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
elementNew(pid_data + i, f(i));
}
return *this;
}
inline PIDeque<T> & assign(const T & f = T()) {return fill(f);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & f) {
//! \~english Same as \a fill().
//! \~russian Тоже самое что и \a fill().
//! \~\sa \a fill(), \a resize()
inline PIDeque<T> & assign(const T & e = T()) { return fill(e); }
//! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & e) {
resize(new_size);
return fill(f);
return fill(e);
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & f) {
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & e) {
_resizeRaw(new_size);
return fill(f);
return fill(e);
}
inline PIDeque<T> & resize(size_t new_size, const T & f = T()) {
//! \~english Sets size of the array, new elements are copied from `e`.
//! \~russian Устанавливает размер массива, новые элементы копируются из `e`.
//! \~\details
//! \~english If `new_size` is greater than the current \a size(),
//! elements are added to the end; the new elements are initialized from `e`.
//! If `new_size` is less than the current \a size(), elements are removed from the end.
//! \~russian Если `new_size` больше чем текущий размер массива \a size(),
//! новые элементы добавляются в конец массива и создаются из `e`.
//! Если `new_size` меньше чем текущий размер массива \a size(),
//! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, const T & e = T()) {
if (new_size == 0) return clear();
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;
if (new_size == 0)
pid_start = (pid_rsize - pid_size) / 2;
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc(new_size, true);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i)
elementNew(pid_data + i, f);
}
return *this;
}
inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t)> f) {
if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size;
if (new_size == 0)
pid_start = (pid_rsize - pid_size) / 2;
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc(new_size, true);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i)
elementNew(pid_data + i, f(i));
} else if (new_size > pid_size) {
expand(new_size, e);
}
return *this;
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
//! \~english Sets size of the array, new elements created by function `f(size_t i)`.
//! \~russian Устанавливает размер массива, новые элементы создаются функцией `f(size_t i)`.
//! \~\details
//! \~english If `new_size` is greater than the current \a size(),
//! elements are added to the end; the new elements created by function `f(size_t i)`.
//! If `new_size` is less than the current \a size(), elements are removed from the end.
//! \~russian Если `new_size` больше чем текущий размер массива \a size(),
//! новые элементы добавляются в конец массива и функцией `f(size_t i)`.
//! Если `new_size` меньше чем текущий размер массива \a size(),
//! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear()
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) {
deleteT(pid_data + pid_start + new_size, pid_size - new_size);
pid_size = new_size;
} else if (new_size > pid_size) {
expand(new_size, f);
}
return *this;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline PIDeque<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
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) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size-new_size));
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size - new_size));
}
alloc(new_size, true);
#endif
alloc_forward(new_size);
return *this;
}
inline void _copyRaw(T * dst, const T * src, size_t size) { newT(dst, src, size); }
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
//! \~\details
//! \~english If you know in advance how large the array will be,
//! you should call this function to prevent reallocations and memory fragmentation.
//! If `new_size` is greater than the current \a capacity(),
//! new storage is allocated, otherwise the function does nothing.
//! This function does not change the \a size() of the array.
//! \~russian Если вы заранее знаете, насколько велик будет массив,
//! вы можете вызвать эту функцию, чтобы предотвратить перераспределение и фрагментацию памяти.
//! Если размер `new_size` больше чем выделенная память \a capacity(),
//! то произойдёт выделение новой памяти и перераспределение массива.
//! Эта функция не изменяет количество элементов в массиве \a size().
//! \~\sa \a size(), \a capacity(), \a resize()
inline PIDeque<T> & reserve(size_t new_size) {
if (new_size <= pid_rsize) return *this;
size_t os = pid_size;
alloc(new_size, true);
const size_t os = pid_size;
alloc_forward(new_size);
pid_size = os;
return *this;
}
inline PIDeque<T> & insert(size_t index, const T & v = T()) {
if (index == pid_size) return push_back(v);
//! \~english Inserts value `e` at `index` position in the array.
//! \~russian Вставляет значение `e` в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than 0 and less than or equal to \a size().
//! \~russian Индекс должен быть больше 0 и меньше или равен \a size().
//! \code
//! PIDeque<int> v{1, 3, 5};
//! v.insert(2, 7);
//! piCout << v; // {1, 3, 7, 5}
//! \endcode
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, const T & e = T()) {
if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
const bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc(pid_size + 1, true);
alloc_forward(pid_size + 1);
if (index < pid_size - 1) {
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));
const size_t os = pid_size - index - 1;
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
}
} else {
alloc(pid_size + 1, false, -1);
if (index > 0)
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
}
elementNew(pid_data + pid_start + index, v);
return *this;
}
inline PIDeque<T> & insert(size_t index, T && v) {
if (index == pid_size) return push_back(v);
PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc(pid_size + 1, true);
if (index < pid_size - 1) {
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));
alloc_backward(pid_size + 1, -1);
if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + 1),
index * sizeof(T));
}
} else {
alloc(pid_size + 1, false, -1);
if (index > 0)
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T));
}
elementNew(pid_data + pid_start + index, std::move(v));
return *this;
}
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & other) {
if (other.isEmpty()) return *this;
assert(&other != this);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
ssize_t os = pid_size - index;
alloc(pid_size + other.pid_size, true);
if (os > 0)
memmove((void*)(&(pid_data[index + pid_start + other.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
} else {
alloc(pid_size + other.pid_size, false, -other.pid_size);
if (index > 0)
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + other.pid_size])), index * sizeof(T));
}
newT(pid_data + pid_start + index, other.pid_data + other.pid_start, other.pid_size);
elementNew(pid_data + pid_start + index, e);
return *this;
}
//! \~english Inserts value `e` at `index` position in the array.
//! \~russian Вставляет значение `e` в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than 0 and less than or equal to \a size().
//! \~russian Индекс должен быть больше 0 и меньше или равен \a size().
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, T && e) {
if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1)
const bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc_forward(pid_size + 1);
if (index < pid_size - 1) {
const size_t os = pid_size - index - 1;
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
}
} else {
alloc_backward(pid_size + 1, -1);
if (index > 0) {
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));
return *this;
}
//! \~english Inserts array `v` at `index` position in the array.
//! \~russian Вставляет массив `v` в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than or equal to 0 and less than or equal to \a size().
//! \~russian Индекс должен быть больше или равен 0 и меньше или равен \a size().
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, const PIDeque<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
printf("error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const bool dir = v.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
const ssize_t os = pid_size - index;
alloc_forward(pid_size + v.pid_size);
if (os > 0) {
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 {
alloc_backward(pid_size + v.pid_size, -v.pid_size);
if (index > 0) {
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);
return *this;
}
//! \~english Inserts the given elements at `index` position in the array.
//! \~russian Вставляет элементы в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than or equal to 0 and less than or equal to \a size().
//! Inserts the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Индекс должен быть больше или равен 0 и меньше или равен \a size().
//! Вставляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const bool dir = init_list.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
const ssize_t os = ssize_t(pid_size) - index;
alloc_forward(pid_size + init_list.size());
if (os > 0) {
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 {
alloc_backward(pid_size + init_list.size(), -init_list.size());
if (index > 0) {
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());
return *this;
}
//! \~english Removes `count` elements from the middle of the array, starting at `index` position.
//! \~russian Удаляет элементы из массива, начиная с позиции `index` в количестве `count`.
//! \~\details
//! \code
//! PIDeque<int> v{1, 3, 7, 5};
//! v.remove(1, 2);
//! piCout << v; // {1, 5}
//! \endcode
//! \~\sa \a resize(), \a insert(), \a removeOne(), \a removeAll(), \a removeWhere()
inline PIDeque<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this;
if (index + count >= pid_size) {
resize(index);
return *this;
}
size_t os = pid_size - index - count;
deleteT(&(pid_data[index + pid_start]), count);
if (os <= index) {
if (os > 0) memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
if (index < pid_size) {
deleteT(pid_data + pid_start + index, pid_size - index);
pid_size = index;
}
} else {
if (index > 0) memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
pid_start += count;
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 {
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;
}
pid_size -= count;
return *this;
}
//! \~english Swaps array `v` other with this array.
//! \~russian Меняет местами массив `v` с этим массивом.
//! \~\details
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIDeque<T> & other) {
piSwap<T*>(pid_data, other.pid_data);
piSwap<T *>(pid_data, other.pid_data);
piSwap<size_t>(pid_size, other.pid_size);
piSwap<size_t>(pid_rsize, other.pid_rsize);
piSwap<ssize_t>(pid_start, other.pid_start);
piSwap<size_t>(pid_start, other.pid_start);
}
typedef int (*CompareFunc)(const T * , const T * );
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);}
inline PIDeque<T> & sort(CompareFunc compare = compare_func) {
piqsort(pid_data + pid_start, pid_size, sizeof(T), (int(*)(const void * , const void * ))compare);
//! \~english Sorts the elements in non-descending order.
//! \~russian Сортировка элементов в порядке возрастания.
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using operator<.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется оператор `operator<`.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort();
//! piCout << v; // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
//! \endcode
//! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp)
inline PIDeque<T> & sort() {
std::sort(begin(), end());
return *this;
}
inline PIDeque<T> & enlarge(llong pid_size) {
llong ns = size_s() + pid_size;
if (ns <= 0) clear();
else resize(size_t(ns));
//! \~english Sorts the elements in non-descending order.
//! \~russian Сортировка элементов в порядке возрастания.
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using the given binary comparison function `comp`.
//! which returns `true` if the first argument is less than (i.e. is ordered before) the second.
//! The signature of the comparison function should be equivalent to the following:
//! \code
//! bool comp(const T &a, const T &b);
//! \endcode
//! 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,
//! otherwise, it will lead to undefined program behavior and memory errors.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`.
//! Функция сравнения, возвращает `true` если первый аргумент меньше
//! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура
//! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для
//! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция
//! [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIDeque<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;});
//! piCout << v; // 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
//! \endcode
//! \~\sa \a sort()
inline PIDeque<T> & sort(std::function<bool(const T & a, const T & b)> comp) {
std::sort(begin(), end(), comp);
return *this;
}
inline PIDeque<T> & removeOne(const T & v) {
for (size_t i = 0; i < pid_size; ++i)
if (pid_data[i + pid_start] == v) {
//! \~english Reverses this array.
//! \~russian Обращает порядок следования элементов этого массива.
//! \~\details
//! \~english This method reverses an array [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
//! The first array element becomes the last, and the last array element becomes the first.
//! The reverse method transposes the elements of the calling array object in place,
//! mutating the array, and returning a reference to the array.
//! \~russian Метод reverse() на месте переставляет элементы массива,
//! на котором он был вызван, изменяет массив и возвращает ссылку на него.
//! Первый элемент массива становится последним, а последний — первым.
//! \~\code
//! PIDeque<int> v{1, 3, 7, 5};
//! v.reverse();
//! piCout << v; // {5, 7, 3, 1}
//! \endcode
//! \~\sa \a reversed()
inline PIDeque<T> & reverse() {
const size_t s2 = pid_size / 2;
for (size_t i = 0; i < s2; ++i) {
piSwap<T>(pid_data[pid_start + i], pid_data[pid_start + pid_size - i - 1]);
}
return *this;
}
//! \~english Returns reversed array.
//! \~russian Возвращает перевернутый массив.
//! \~\details
//! \~english Returns a copy of the array with elements in reverse order.
//! The first array element becomes the last, and the last array element becomes the first.
//! \~russian Возвращает копию массива с элементами в обратном порядке.
//! Первый элемент массива становится последним, а последний — первым.
//! \~\sa \a reverse()
inline PIDeque<T> reversed() const {
PIDeque<T> ret(*this);
return ret.reverse();
}
//! \~english Increases or decreases the size of the array by `add_size` elements.
//! \~russian Увеличивает или уменьшает размер массива на `add_size` элементов.
//! \~\details
//! \~english If `add_size > 0` then elements are added to the end of the array.
//! If `add_size < 0` then elements are removed from the end of the array.
//! If `add_size < 0` and there are fewer elements in the array than specified, then the array becomes empty.
//! \~russian Если `add_size > 0`, то в конец массива добавляются элементы.
//! Если `add_size < 0`, то с конца массива удаляются элементы.
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize()
inline PIDeque<T> & enlarge(ssize_t add_size, const T & e = T()) {
const ssize_t ns = size_s() + add_size;
if (ns <= 0)
clear();
else
resize(size_t(ns), e);
return *this;
}
//! \~english Remove no more than one element equal `e`.
//! \~russian Удаляет первый элемент, который равен элементу `e`.
//! \~\details
//! \~\code
//! PIDeque<int> v{3, 2, 5, 2, 7};
//! v.removeOne(2);
//! piCout << v; // {3, 5, 2, 7}
//! \endcode
//! \~\sa \a remove(), \a removeAll(), \a removeWhere()
inline PIDeque<T> & removeOne(const T & e) {
for (size_t i = 0; i < pid_size; ++i) {
if (pid_data[i + pid_start] == e) {
remove(i);
return *this;
}
}
return *this;
}
inline PIDeque<T> & removeAll(const T & v) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i)
if (pid_data[i + pid_start] == v) {
remove(i);
--i;
//! \~english Remove all elements equal `e`.
//! \~russian Удаляет все элементы, равные элементу `e`.
//! \~\details
//! \~\code
//! PIDeque<int> v{3, 2, 5, 2, 7};
//! v.removeAll(2);
//! piCout << v; // {3, 5, 7}
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeAll(const T & e) {
ssize_t j = indexOf(e);
if (j != -1) {
for (size_t i = j + 1; i < pid_size; ++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;
}
inline PIDeque<T> & push_back(const T & v) {
alloc(pid_size + 1, true);
//! \~english Remove all elements in the array
//! passes the test implemented by the provided function `test`.
//! \~russian Удаляет все элементы, удовлетворяющие условию,
//! заданному в передаваемой функции `test`.
//! \~\details
//! \~\code
//! PIDeque<int> v{3, 2, 5, 2, 7};
//! v.removeWhere([](const int & i){return i > 2;});
//! piCout << v; // {2, 2}
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) {
ssize_t j = indexWhere(test);
if (j != -1) {
for (size_t i = j + 1; i < pid_size; ++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;
}
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~english If size() is less than capacity(), which is most often
//! then the addition will be very fast.
//! In any case, the addition is fast and does not depend on the size of the array.
//! If the new size() is greater than capacity()
//! then all iterators and references
//! (including the past-the-end iterator) are invalidated.
//! Otherwise only the past-the-end iterator is invalidated.
//! \~russian Если size() меньше capacity(), что часто бывает,
//! то добавление будет очень быстрым.
//! В любом случае добавление быстрое и не зависит от размера массива.
//! Если новый size() больше, чем capacity(),
//! то все итераторы и указатели становятся нерабочими.
//! В противном случае все, кроме итераторов, указывающих на конец массива,
//! остаются в рабочем состоянии.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.push_back(4);
//! v.push_back(5);
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a push_front(), \a append(), \a prepend(), \a insert()
inline PIDeque<T> & push_back(const T & e) {
alloc_forward(pid_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, v);
elementNew(pid_data + pid_start + pid_size - 1, e);
return *this;
}
inline PIDeque<T> & push_back(T && v) {
alloc(pid_size + 1, true);
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a push_back()
inline PIDeque<T> & push_back(T && e) {
alloc_forward(pid_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, std::move(v));
elementNew(pid_data + pid_start + pid_size - 1, std::move(e));
return *this;
}
inline PIDeque<T> & append(const T & v) {return push_back(v);}
inline PIDeque<T> & append(T && v) {return push_back(std::move(v));}
inline PIDeque<T> & append(const PIDeque<T> & t) {
assert(&t != this);
size_t ps = pid_size;
alloc(pid_size + t.pid_size, true);
newT(pid_data + ps + pid_start, t.pid_data + t.pid_start, t.pid_size);
//! \~english Appends the given elements to the end of the array.
//! \~russian Добавляет элементы в конец массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back()
inline PIDeque<T> & push_back(std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const size_t ps = pid_size;
alloc_forward(pid_size + init_list.size());
newT(pid_data + pid_start + ps, init_list.begin(), init_list.size());
return *this;
}
inline PIDeque<T> & operator <<(const T & v) {return push_back(v);}
inline PIDeque<T> & operator <<(T && v) {return push_back(std::move(v));}
inline PIDeque<T> & operator <<(const PIDeque<T> & t) {return append(t);}
inline PIDeque<T> & push_front(const T & v) {insert(0, v); return *this;}
inline PIDeque<T> & push_front(T && v) {insert(0, std::move(v)); return *this;}
inline PIDeque<T> & prepend(const T & v) {return push_front(v);}
inline PIDeque<T> & prepend(T && v) {return push_front(std::move(v));}
//! \~english Appends the given array `v` to the end of the array.
//! \~russian Добавляет массив `v` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a push_back()
inline PIDeque<T> & push_back(const PIDeque<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const size_t ps = pid_size;
alloc_forward(pid_size + v.pid_size);
newT(pid_data + ps + pid_start, v.pid_data + v.pid_start, v.pid_size);
return *this;
}
inline PIDeque<T> & pop_back() {if (pid_size == 0) return *this; resize(pid_size - 1); return *this;}
inline PIDeque<T> & pop_front() {if (pid_size == 0) return *this; remove(0); return *this;}
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~english If size() is less than capacity(), which is most often
//! then the addition will be very fast.
//! In any case, the addition is fast and does not depend on the size of the array.
//! If the new size() is greater than capacity()
//! then all iterators and references
//! (including the past-the-end iterator) are invalidated.
//! Otherwise only the past-the-end iterator is invalidated.
//! \~russian Если size() меньше capacity(), что часто бывает,
//! то добавление будет очень быстрым.
//! В любом случае добавление быстрое и не зависит от размера массива.
//! Если новый size() больше, чем capacity(),
//! то все итераторы и указатели становятся нерабочими.
//! В противном случае все, кроме итераторов, указывающих на конец массива,
//! остаются в рабочем состоянии.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.append(4);
//! v.append(5);
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a prepend(), \a push_front(), \a push_back(), \a insert()
inline PIDeque<T> & append(const T & e) { return push_back(e); }
inline T take_back() {T t(back()); pop_back(); return t;}
inline T take_front() {T t(front()); pop_front(); return t;}
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a append()
inline PIDeque<T> & append(T && e) { return push_back(std::move(e)); }
template <typename ST>
PIDeque<ST> toType() const {
//! \~english Appends the given elements to the end of the array.
//! \~russian Добавляет элементы в конец массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIDeque<T> & append(std::initializer_list<T> init_list) { return push_back(init_list); }
//! \~english Appends the given array `v` to the end of the array.
//! \~russian Добавляет массив `v` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.append(PIDeque<int>{4, 5});
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIDeque<T> & append(const PIDeque<T> & v) { return push_back(v); }
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v << 4 << 5;
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIDeque<T> & operator<<(const T & e) { return push_back(e); }
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v << 4 << 5;
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIDeque<T> & operator<<(T && e) { return push_back(std::move(e)); }
//! \~english Appends the given array `v` to the end of the array.
//! \~russian Добавляет массив `v` в конец массива.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v << PIDeque<int>{4, 5};
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append(), \a push_back()
inline PIDeque<T> & operator<<(const PIDeque<T> & v) { return append(v); }
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english If there is free space at the beginning of the array,
//! which is most often, then the addition will be very fast.
//! In any case, the addition is fast and does not depend on the size of the array.
//! If there is no free space at the beginning of the array
//! then all iterators and references
//! (including the past-the-begin iterator) are invalidated.
//! Otherwise only the past-the-begin iterator is invalidated.
//! \~russian Если в начале массива имеется свободное место,
//! что часто бывает, то добавление будет очень быстрым.
//! В любом случае добавление быстрое и не зависит от размера массива.
//! Если в начале массива нет свободного места,
//! то все итераторы и указатели становятся нерабочими.
//! В противном случае все, кроме итераторов указывающих, на начало массива,
//! остаются в рабочем состоянии.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.push_front(4);
//! v.push_front(5);
//! piCout << v; // {5, 4, 1, 2, 3}
//! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIDeque<T> & push_front(const T & e) {
if (isEmpty()) return push_back(e);
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, e);
return *this;
}
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a push_front()
inline PIDeque<T> & push_front(T && 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;
}
//! \~english Appends the given array `v` to the begin of the array.
//! \~russian Добавляет массив `v` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.push_front(PIDeque<int>{4, 5});
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a push_front()
inline PIDeque<T> & push_front(const PIDeque<T> & v) { return insert(0, v); }
//! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIDeque<T> & push_front(std::initializer_list<T> init_list) { return insert(0, init_list); }
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english If there is free space at the beginning of the array,
//! which is most often, then the addition will be very fast.
//! In any case, the addition is fast and does not depend on the size of the array.
//! If there is no free space at the beginning of the array
//! then all iterators and references
//! (including the past-the-begin iterator) are invalidated.
//! Otherwise only the past-the-begin iterator is invalidated.
//! \~russian Если в начале массива имеется свободное место,
//! что часто бывает, то добавление будет очень быстрым.
//! В любом случае добавление быстрое и не зависит от размера массива.
//! Если в начале массива нет свободного места,
//! то все итераторы и указатели становятся нерабочими.
//! В противном случае все, кроме итераторов указывающих, на начало массива,
//! остаются в рабочем состоянии.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.prepend(4);
//! v.prepend(5);
//! piCout << v; // {5, 4, 1, 2, 3}
//! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIDeque<T> & prepend(const T & e) { return push_front(e); }
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a prepend()
inline PIDeque<T> & prepend(T && e) { return push_front(std::move(e)); }
//! \~english Appends the given array `v` to the begin of the array.
//! \~russian Добавляет массив `v` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.prepend(PIDeque<int>{4, 5});
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a prepend()
inline PIDeque<T> & prepend(const PIDeque<T> & v) { return push_front(v); }
//! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIDeque<T> & prepend(std::initializer_list<T> init_list) { return push_front(init_list); }
//! \~english Remove one element from the end of the array.
//! \~russian Удаляет один элемент с конца массива.
//! \~\details
//! \~english Deleting an element from the end is very fast
//! and does not depend on the size of the array.
//! \~russian Удаление элемента с конца выполняется очень быстро
//! и не зависит от размера массива.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.pop_back();
//! piCout << v; // {1, 2}
//! \endcode
//! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_back() {
if (pid_size == 0) return *this;
elementDelete(pid_data[pid_size + pid_start - 1]);
pid_size = pid_size - 1;
return *this;
}
//! \~english Remove one element from the begining of the array.
//! \~russian Удаляет один элемент с начала массива.
//! \~\details
//! \~english Removing an element from the beginning takes longer than from the end.
//! This time is directly proportional to the size of the array.
//! All iterators and references are invalidated.
//! \~russian Удаление элемента с начала выполняется дольше, чем с конца.
//! Это время прямопропорционально размеру массива.
//! При удалении элемента все итераторы и указатели становятся нерабочими.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! v.pop_front();
//! piCout << v; // {2, 3}
//! \endcode
//! \~\sa \a pop_back(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_front() {
if (pid_size == 0) return *this;
elementDelete(pid_data[pid_start]);
pid_start += 1;
pid_size -= 1;
return *this;
}
//! \~english Remove one element from the end of the array and return it.
//! \~russian Удаляет один элемент с начала массива и возвращает его.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! piCout << v.take_back(); // 3
//! piCout << v; // {1, 2}
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() {
const T e(back());
pop_back();
return e;
}
//! \~english Remove one element from the begining of the array and return it.
//! \~russian Удаляет один элемент с конца массива и возвращает его.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! piCout << v.take_front(); // 1
//! piCout << v; // {2, 3}
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() {
const T e(front());
pop_front();
return e;
}
//! \~english Returns an array converted to another type.
//! \~russian Возвращает конвертированный в другой тип массив.
//! \~\details
//! \~\code
//! PIDeque<double> v{1.1, 2.5, 3.8};
//! PIDeque<int> v2 = v.toType<int>();
//! piCout << v2; // {1, 2, 3}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size);
for (uint i = 0; i < pid_size; ++i)
ret.reserve(pid_size);
for (size_t i = 0; i < pid_size; ++i) {
ret[i] = ST(pid_data[i + pid_start]);
}
return ret;
}
const PIDeque<T> & forEach(std::function<void(const T &)> f) const {
for (uint i = 0; i < pid_size; ++i)
f(pid_data[i + pid_start]);
return *this;
}
PIDeque<T> copyForEach(std::function<T(const T &)> f) const {
PIDeque<T> ret; ret.reserve(pid_size);
for (uint i = 0; i < pid_size; ++i)
ret << f(pid_data[i + pid_start]);
return ret;
}
PIDeque<T> & forEachInplace(std::function<T(const T &)> f) {
for (uint i = 0; i < pid_size; ++i)
pid_data[i + pid_start] = f(pid_data[i + pid_start]);
return *this;
}
template <typename ST>
PIDeque<ST> toType(std::function<ST(const T &)> f) const {
PIDeque<ST> ret; ret.reserve(pid_size);
for (uint i = 0; i < pid_size; ++i)
ret << f(pid_data[i + pid_start]);
//! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `bool test(const T & e)`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`.
//! \~\details
//! \~\code
//! PIDeque<int> v{3, 2, 5, 2, 7};
//! PIDeque<int> v2 = v.filter([](const int & i){return i > 2;});
//! piCout << v2; // {3, 5, 7}
//! \endcode
//! \~\sa \a map(), \a any(), \a every()
inline PIDeque<T> filter(std::function<bool(const T & e)> test) const {
PIDeque<T> ret;
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
if (test(pid_data[i])) ret << pid_data[i];
}
return ret;
}
inline PIDeque<PIDeque<T>> reshape(size_t rows, size_t cols, int order = byRow) const {
//! \~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.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details
//! \~russian Не позволяет изменять элементы массива.
//! Для редактирования элементов используйте функцию вида `void f(T & e)`.
//! \~english Does not allow changing array elements.
//! To edit elements, use the function like `void f(T & e)`
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4, 5};
//! int s = 0;
//! v.forEach([&s](const int & e){s += e;});
//! piCout << s; // 15
//! \endcode
//! \~\sa \a filter(), \a map(), \a reduce(), \a any(), \a every()
inline void forEach(std::function<void(const T & e)> f) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
f(pid_data[i]);
}
}
//! \~english Execute function `void f(T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(T & e)` для каждого элемента массива.
//! \~\details
//! \~english Overloaded function.
//! Allows you to change the elements of the array.
//! \~russian Перегруженая функция.
//! Позволяет изменять элементы массива.
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4, 5};
//! v.forEach([](int & e){e++;});
//! piCout << v; // {2, 3, 4, 5, 6}
//! \endcode
//! \~\sa \a filter(), \a map(), \a reduce(), \a any(), \a every()
inline PIDeque<T> & forEach(std::function<void(T & e)> f) {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
f(pid_data[i]);
}
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
//! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции
//! `ST f(const T & e)` для каждого элемента массива.
//! \~\details
//! \~english Calls a provided function`ST f(const T & e)`
//! once for each element in an array, in order,
//! and constructs a new array from the results.
//! \~russian Метод `map` вызывает переданную функцию `ST f(const T & e)`
//! один раз для каждого элемента в порядке их появления от начала к концу (слева на право)
//! и конструирует новый массив из результатов её вызова.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"1", "2", "3"}
//! \endcode
//! \~\sa \a forEach(), \a reduce()
template<typename ST>
inline PIDeque<ST> map(std::function<ST(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(pid_data[i]);
}
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)`
//! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
//! к каждому элементу массива (слева-направо), возвращает одно значение.
//! \~\details
//! \~english The reduce() method performs the `f` function
//! once for each element in the array.
//! If the `initial` argument is passed when calling reduce(),
//! then when the function `f` is called for the first time,
//! the value of `acc` will be assigned to `initial`.
//! If the array is empty, the value `initial` will be returned.
//! \param f is a function like `ST f(const T & e, const ST & acc)`,
//! executed for each element of the array. It takes two arguments:
//! * **e** - current element of the array
//! * **acc** - accumulator accumulating the value
//! which this function returns after visiting the next element
//!
//! \param initial _optional_ Object used as the second argument
//! when the `f` function is first called.
//! \~russian Метод reduce() выполняет функцию `f`
//! один раз для каждого элемента, присутствующего в массиве от начала к концу (слева на право).
//! Если при вызове reduce() передан аргумент `initial`,
//! то при первом вызове функции `f` значение `acc`
//! будет равным значению `initial`.
//! Если массив пустой то будет возвращено значение `initial`.
//! \param f Функция, вида `ST f(const T & e, const ST & acc)`,
//! выполняющаяся для каждого элемента массива.
//! Она принимает два аргумента:
//! * **e** - текущий элемент массива
//! * **acc** - аккумулятор, аккумулирующий значение
//! которое возвращает эта функция после посещения очередного элемента
//!
//! \param initial _опциональный_ Объект,
//! используемый в качестве второго аргумента при первом вызове функции `f`.
//!
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4, 5};
//! int s = v.reduce<int>([](const int & e, const int & acc){return e + acc;});
//! piCout << s; // 15
//! \endcode
//! \~\sa \a reduceIndexed(), \a reduceReverse(), \a reduceReverseIndexed(), \a forEach(), \a map()
template<typename ST>
inline ST reduce(std::function<ST(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(pid_data[i], 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.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details
//! \~russian
//! \param rows размер внешнего массива
//! \param cols размер внутренних массивов
//! \param order порядок обхода исходного массива, задаётся с помощью \a ReshapeOrder
//! \~english
//! \param rows size external array
//! \param cols size internal arrays
//! \param order the order of traversing the source array is set using \a ReshapeOrder
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4};
//! PIDeque<PIDeque<int>> m1 = v.reshape(2,2);
//! piCout << m1; // {{1, 2}, {3, 4}}
//! PIDeque<PIDeque<int>> m2 = v.reshape(2,2, ReshapeByColumn);
//! piCout << m2; // {{1, 3}, {2, 4}}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a flatten()
inline PIDeque<PIDeque<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
PIDeque<PIDeque<T>> ret;
if (isEmpty()) return ret;
assert(rows*cols == pid_size);
ret.resize(rows);
if (order == byRow) {
for (size_t r = 0; r < rows; r++)
ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols);
#ifndef NDEBUG
if (rows * cols != pid_size) {
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
}
if (order == byColumn) {
#endif
assert(rows * cols == pid_size);
ret.expand(rows);
if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols);
for (size_t c = 0; c < cols; c++)
ret[r][c] = pid_data[c*rows + r];
ret[r] = PIDeque<T>(&(pid_data[r * cols]), cols);
}
}
if (order == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) {
ret[r].expand(cols);
for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c * rows + r];
}
}
}
return ret;
}
template<typename C, typename std::enable_if<
std::is_same<T, PIDeque<C>>::value
, int>::type = 0>
inline PIDeque<C> reshape(int order = byRow) const {
//! \~english Changes the dimension of the array, creates a one-dimensional array from a two-dimensional array.
//! \~russian Изменяет размерность массива, из двухмерный массива создает одномерный.
//! \~\details
//! \~russian Делает массив плоским.
//! Порядок обхода исходного массива задаётся с помощью \a ReshapeOrder.
//! \~english Makes the array flat.
//! Еhe order of traversing the source array is set using \a ReshapeOrder.
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4, 5, 6};
//! PIDeque<PIDeque<int>> xv = v.reshape(3,2);
//! piCout << xv; // {{1, 2}, {3, 4}, {5, 6}}
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if<std::is_same<T, PIDeque<C>>::value, int>::type = 0>
inline PIDeque<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> ret;
if (isEmpty()) return ret;
size_t rows = size();
size_t cols = at(0).size();
const size_t rows = size();
const size_t cols = at(0).size();
ret.reserve(rows * cols);
if (order == byRow) {
for (size_t r = 0; r < rows; r++)
if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) {
ret.append(at(r));
}
}
if (order == byColumn) {
for (size_t c = 0; c < cols; c++)
for (size_t r = 0; r < rows; r++)
if (order == ReshapeByColumn) {
for (size_t c = 0; c < cols; c++) {
for (size_t r = 0; r < rows; r++) {
ret << at(r)[c];
}
}
}
ret.resize(rows * cols);
return ret;
}
//! \~english Changes the dimension of the two-dimensional array.
//! \~russian Изменяет размерность двухмерного массива.
//! \~\details
//! \~russian
//! \param rows размер внешнего массива
//! \param cols размер внутренних массивов
//! \param order порядок обхода исходного массива, задаётся с помощью \a ReshapeOrder
//! \~english
//! \param rows size external array
//! \param cols size internal arrays
//! \param order the order of traversing the source array is set using \a ReshapeOrder
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4, 5, 6};
//! PIDeque<PIDeque<int>> xv = v.reshape(3,2);
//! piCout << xv; // {{1, 2}, {3, 4}, {5, 6}}
//! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if<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 {
PIDeque<C> fl = flatten<C>();
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:
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
inline void _reset() {
pid_size = 0;
pid_rsize = 0;
pid_start = 0;
pid_data = nullptr;
}
inline size_t asize(ssize_t s) {
if (s <= 0) return 0;
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s))
return pid_rsize + pid_rsize;
ssize_t t = 0, s_ = s - 1;
while (s_ >> t)
if (pid_rsize * 2 >= size_t(s) && pid_rsize < size_t(s)) {
return pid_rsize * 2;
}
size_t t = _PIContainerConstants<T>::minCountPoT();
s -= 1;
while (s >> t) {
++t;
}
return (1 << t);
}
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) {
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]);
}
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) {
PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy((void*)(dst), (const void*)(src), s * sizeof(T));
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i)
elementDelete(d[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) {
PIINTROSPECTION_CONTAINER_USED(T, s)
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, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if (d != nullptr) {
for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]);
}
}
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, const 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, const T & from) {
new (to) T(from);
}
inline void checkMove(bool direction) {
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() {
if (pid_size >= 4) {
if (pid_size < pid_rsize / 6) {
if (pid_start < ssize_t(pid_size + pid_size) || pid_start > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) {
ssize_t ns = (pid_rsize - pid_size) / 2;
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;
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;
}
}
}
} else {
ssize_t ns = (pid_rsize - pid_size) / 2;
const size_t ns = (pid_rsize - pid_size) / 2;
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;
}
}
}
inline void alloc(size_t new_size, bool direction, ssize_t start_offset = 0) { // direction == true -> alloc forward
if (direction) {
if (pid_start + new_size <= pid_rsize) {
pid_size = new_size;
checkMove(direction);
return;
}
pid_size = new_size;
size_t as = asize(pid_start + new_size);
if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T)));
assert(p_d);
pid_data = p_d;
pid_rsize = as;
}
} else {
size_t as;
if (pid_start + start_offset < 0)
as = asize(pid_rsize - start_offset);
else as = pid_rsize;
if (as > pid_rsize) {
T * td = (T*)(malloc(as * sizeof(T)));
ssize_t ns = pid_start + as - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
if (pid_rsize > 0 && pid_data != 0) {
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
dealloc();
}
pid_data = td;
pid_rsize = as;
pid_start = ns;
}
pid_start += start_offset;
inline void alloc_forward(size_t new_size) {
if (pid_start + new_size <= pid_rsize) {
pid_size = new_size;
checkMove(direction);
if (pid_start > 0) checkMove();
return;
}
pid_size = new_size;
const size_t as = asize(pid_start + new_size);
if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), as * sizeof(T)));
#ifndef NDEBUG
if (!p_d) {
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
pid_data = p_d;
pid_rsize = as;
}
}
T * pid_data;
size_t pid_size, pid_rsize;
ssize_t pid_start;
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) {
const size_t as = ssize_t(pid_start) + start_offset < 0 ? asize(pid_rsize - start_offset) : pid_rsize;
if (as > pid_rsize) {
T * td = reinterpret_cast<T *>(malloc(as * sizeof(T)));
const size_t ns = pid_start + as - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
if (pid_rsize > 0 && pid_data != 0) {
memcpy(reinterpret_cast<void *>(td + ns), reinterpret_cast<const void *>(pid_data + pid_start), pid_size * sizeof(T));
dealloc();
}
pid_data = td;
pid_rsize = as;
pid_start = ns;
}
pid_start += start_offset;
pid_size = new_size;
checkMove();
}
inline void expand(size_t new_size, const T & e = T()) {
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, 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;
};
#ifdef PIP_STD_IOSTREAM
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename T>
inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;}
#endif
template<typename T>
inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s.space();
s.setControl(0, true);
inline std::ostream & operator<<(std::ostream & s, const PIDeque<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1)
s << ", ";
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControl();
return s;
}
#endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename T>
inline PICout operator<<(PICout s, const PIDeque<T> & v) {
s.space();
s.saveAndSetControls(0);
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControls();
return s;
}
template<typename T> inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {f.swap(s);}
template<typename T>
inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {
f.swap(s);
}
#endif // PIDEQUE_H

View File

@@ -1,187 +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,413 +1,1010 @@
/*! @file pimap.h
* @brief Associative array with custom types of key and value
*
* This file declares PIMap
*/
//! \addtogroup Containers
//! \{
//! \file pimap.h
//! \brief
//! \~english Declares \a PIMap
//! \~russian Объявление \a PIMap
//! \~\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
Associative array with custom types of key and value
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Associative array with custom types of key and value
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 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.
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/>.
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 PIMAP_H
#define PIMAP_H
#include "pivector.h"
#include "pideque.h"
#include "pipair.h"
#include "pivector.h"
template<class T>
void piQuickSort(T * a, ssize_t N) {
if (N < 1) return;
if (N < 46) {
T tmp;
ssize_t i,j;
for(i=1; i<=N; i++) {
tmp = a[i];
j = i-1;
while(tmp<a[j] && j>=0) {
a[j+1] = a[j];
j = j-1;
}
a[j+1] = tmp;
}
} else {
ssize_t i = 0, j = N;
T & p(a[N >> 1]);
do {
while (a[i] < p) i++;
while (a[j] > p) j--;
if (i <= j) {
if (i != j) {
//piCout << "swap" << i << j << a[i] << a[j];
piSwap<T>(a[i], a[j]);
}
i++; j--;
}
} while (i <= j);
if (j > 0) piQuickSort(a, j);
if (N > i) piQuickSort(a + i, N - i);
}
}
template <typename Key, typename T>
template<typename Key, typename T>
class PIMapIteratorConst;
template<typename Key, typename T>
class PIMapIteratorConstReverse;
template<typename Key, typename T>
class PIMapIterator;
template<typename Key, typename T>
class PIMapIteratorReverse;
template <typename Key, typename T>
//! \addtogroup Containers
//! \{
//! \class PIMap
//! \brief
//! \~english Associative array.
//! \~russian Словарь.
//! \~\}
//! \details
//! \~english
//! A collection of key/value pairs, from which you retrieve a value using its associated key.
//! There is a finite number of keys in the map, and each key has exactly one value associated with it.
//! \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().
//! A key in the Map may only occur once.
//! \~russian
//! Словари, в принципе, похожи на обычные, используемые в повседневной жизни.
//! Они хранят элементы одного и того же типа, индексируемые ключевыми значениями.
//! Достоинство словаря в том, что он позволяет быстро получать значение,
//! ассоциированное с заданным ключом.
//! Ключи должны быть уникальными.
//! Элемент
//! В контейнеры этого типа заносятся элементы вместе с ключами,
//! по которым их можно найти, которыми могут выступать значения любого типа.
//! \a operator [] позволяет получить доступ к элементу по ключу,
//! и если такого эелемента не было, то он будет создан.
template<typename Key, typename T>
class PIMap {
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend class PIMapIterator;
public:
PIMap() {;}
PIMap(const PIMap<Key, T> & other) {*this = other;}
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
virtual ~PIMap() {;}
template<typename Key1, typename T1>
friend class PIMapIteratorConst;
template<typename Key1, typename T1>
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>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMap<Key1, T1> & v);
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key1, T1> & v);
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
public:
typedef T mapped_type;
typedef Key key_type;
typedef PIPair<Key, T> value_type;
//! \~english Constructs an empty map.
//! \~russian Создает пустой словарь.
inline PIMap() {}
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIMap(const PIMap<Key, T> & other): pim_content(other.pim_content), pim_index(other.pim_index) {}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIMap(PIMap<Key, T> && other): pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
//! \~english Contructs map from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Создает словарь из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\details
//! \~\code
//! PIMap <int, PIString> m{{1, "a"}, {2, "b"}};
//! piCout << m; // {1: a, 2: b}
//! \endcode
inline PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
for (auto i: init_list) {
insert(std::get<0>(i), std::get<1>(i));
}
}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIMap<Key, T> & operator=(const PIMap<Key, T> & other) {
if (this == &other) return *this;
clear();
pim_content = other.pim_content;
pim_index = other.pim_index;
pim_index = other.pim_index;
return *this;
}
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIMap<Key, T> & operator=(PIMap<Key, T> && other) {
swap(other);
return *this;
}
typedef T mapped_type;
typedef Key key_type;
typedef PIPair<Key, T> value_type;
class iterator {
friend class PIMap<Key, T>;
private:
iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
void operator ++() {++pos;}
void operator ++(int) {++pos;}
void operator --() {--pos;}
void operator --(int) {--pos;}
bool operator ==(const iterator & it) const {return (pos == it.pos);}
bool operator !=(const iterator & it) const {return (pos != it.pos);}
iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
T & value() { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
inline PIPair<Key, T> operator*() const {
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator++() { ++pos; }
void operator++(int) { ++pos; }
void operator--() { --pos; }
void operator--(int) { --pos; }
bool operator==(const iterator & it) const { return (pos == it.pos); }
bool operator!=(const iterator & it) const { return (pos != it.pos); }
};
class reverse_iterator {
friend class PIMap<Key, T>;
private:
reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
reverse_iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
void operator ++() {--pos;}
void operator ++(int) {--pos;}
void operator --() {++pos;}
void operator --(int) {++pos;}
bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
reverse_iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
T & value() const { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
inline PIPair<Key, T> operator*() const {
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator++() { --pos; }
void operator++(int) { --pos; }
void operator--() { ++pos; }
void operator--(int) { ++pos; }
bool operator==(const reverse_iterator & it) const { return (pos == it.pos); }
bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); }
};
class const_iterator {
friend class PIMap<Key, T>;
private:
const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
const_iterator(): parent(0), pos(0) {}
const value_type operator *() const {return parent->_pair(pos);}
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
void operator ++() {++pos;}
void operator ++(int) {++pos;}
void operator --() {--pos;}
void operator --(int) {--pos;}
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
mutable value_type cval;
const_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); }
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
const T & value() const { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
void operator++() { ++pos; }
void operator++(int) { ++pos; }
void operator--() { --pos; }
void operator--(int) { --pos; }
bool operator==(const const_iterator & it) const { return (pos == it.pos); }
bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
};
class const_reverse_iterator {
friend class PIMap<Key, T>;
private:
const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
const_reverse_iterator(): parent(0), pos(0) {}
const value_type operator *() const {return parent->_pair(pos);}
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
void operator ++() {--pos;}
void operator ++(int) {--pos;}
void operator --() {++pos;}
void operator --(int) {++pos;}
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
mutable value_type cval;
const_reverse_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); }
void operator++() { --pos; }
void operator++(int) { --pos; }
void operator--() { ++pos; }
void operator--(int) { ++pos; }
bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); }
bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); }
};
iterator begin() {return iterator(this, 0);}
iterator end() {return iterator(this, size());}
const_iterator begin() const {return const_iterator(this, 0);}
const_iterator end() const {return const_iterator(this, size());}
const_iterator constBegin() const {return const_iterator(this, 0);}
const_iterator constEnd() const {return const_iterator(this, size());}
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);}
PIMapIterator<Key, T> makeIterator() const {return PIMapIterator<Key, T>(*this);}
PIMapIterator<Key, T> makeReverseIterator() const {return PIMapIterator<Key, T>(*this, true);}
//! \~english Iterator to the first element.
//! \~russian Итератор на первый элемент.
inline iterator begin() { return iterator(this, 0); }
size_t size() const {return pim_content.size();}
int size_s() const {return pim_content.size_s();}
size_t length() const {return pim_content.size();}
bool isEmpty() const {return (pim_content.size() == 0);}
T & operator [](const Key & key) {
//! \~english Iterator to the element following the last element.
//! \~russian Итератор на элемент, следующий за последним элементом.
inline iterator end() { return iterator(this, size()); }
inline const_iterator begin() const { return const_iterator(this, 0); }
inline 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); }
//! \~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); }
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); }
//! \relatesalso PIMapIteratorConst
inline PIMapIteratorConst<Key, T> makeIterator() const { return PIMapIteratorConst<Key, T>(*this); }
//! \relatesalso PIMapIterator
inline PIMapIterator<Key, T> makeIterator() { return PIMapIterator<Key, T>(*this); }
//! \relatesalso PIMapIteratorConstReverse
inline PIMapIteratorConstReverse<Key, T> makeReverseIterator() const { return PIMapIteratorConstReverse<Key, T>(*this); }
//! \relatesalso PIMapIteratorReverse
inline PIMapIteratorReverse<Key, T> makeReverseIterator() { return PIMapIteratorReverse<Key, T>(*this); }
//! \~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(); }
//! \~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(); }
//! \~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(); }
//! \~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); }
//! \~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); }
//! \~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);
ssize_t i = _find(key, f);
if (f) return pim_content[pim_index[i].index];
const ssize_t i = _find(key, f);
if (f) return _value(i);
pim_content.push_back(T());
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
return pim_content.back();
}
const T operator [](const Key & key) const {bool f(false); ssize_t i = _find(key, f); if (f) return pim_content[pim_index[i].index]; return T();}
const T at(const Key & key) const {return (*this)[key];}
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) {
//! \~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);
const ssize_t i = _find(key, f);
return _value(i);
}
//! \~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);
return ret;
}
//! \~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
if (&other == this) {
printf("error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
}
#endif
assert(&other != this);
if (other.isEmpty()) return *this;
if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}
if (other.size() == 2) {insert(other.pim_index[0].key, other.pim_content[0]); insert(other.pim_index[1].key, other.pim_content[1]); return *this;}
for (int i = 0; i < other.pim_index.size_s(); ++i)
if (other.size() == 1) {
insert(other.pim_index[0].key, other.pim_content[0]);
return *this;
}
if (other.size() == 2) {
insert(other.pim_index[0].key, other.pim_content[0]);
insert(other.pim_index[1].key, other.pim_content[1]);
return *this;
}
for (int i = 0; i < other.pim_index.size_s(); ++i) {
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
}
return *this;
}
bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content && pim_index == t.pim_index);}
bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content || pim_index != t.pim_index);}
bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
//! \~english Compare operator with array `m`.
//! \~russian Оператор сравнения с массивом `m`.
inline bool operator==(const PIMap<Key, T> & m) const { return (pim_content == m.pim_content && pim_index == m.pim_index); }
PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;}
//! \~english Compare operator with array `m`.
//! \~russian Оператор сравнения с массивом `m`.
inline bool operator!=(const PIMap<Key, T> & m) const { return (pim_content != m.pim_content || pim_index != m.pim_index); }
PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
PIMap<Key, T> & clear() {pim_content.clear(); pim_index.clear(); return *this;}
void swap(PIMap<Key, T> & other) {
//! \~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;
}
//! \~english Tests if element with value `value` exists in the array.
//! \~russian Проверяет наличие элемента со значением `value` в массиве.
inline bool containsValue(const T & value) const { return pim_content.contains(value); }
//! \~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_index.reserve(new_size);
return *this;
}
//! \~english Remove element with key `key` from the array.
//! \~russian Удаляет элемент с ключом `key` из массива.
inline PIMap<Key, T> & remove(const Key & key) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) _remove(i);
return *this;
}
//! \~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) {
const auto & mi(pim_index[i]);
if (test(mi.key, pim_content[mi.index])) {
_remove(i);
--i;
}
}
return *this;
}
//! \~english Same as \a remove().
//! \~russian Синоним функции \a remove().
inline PIMap<Key, T> & erase(const Key & key) { return remove(key); }
//! \~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_index.clear();
return *this;
}
//! \~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_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);
ssize_t i = _find(key, f);
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
const ssize_t i = _find(key, f);
if (f) {
pim_content[pim_index[i].index] = value;
_value(i) = value;
} else {
pim_content.push_back(value);
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
}
return *this;
}
PIMap<Key, T> & insert(const Key & key, T && value) {
inline PIMap<Key, T> & insert(const Key & key, T && value) {
bool f(false);
ssize_t i = _find(key, f);
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
const ssize_t i = _find(key, f);
if (f) {
pim_content[pim_index[i].index] = std::move(value);
_value(i) = std::move(value);
} else {
pim_content.push_back(std::move(value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
}
return *this;
}
const T value(const Key & key, const T & default_ = T()) const {bool f(false); ssize_t i = _find(key, f); if (!f) return default_; return pim_content[pim_index[i].index];}
PIVector<T> values() const {return pim_content;}
Key key(const T & value_, const Key & default_ = Key()) const {for (int i = 0; i < pim_index.size_s(); ++i) if (pim_content[pim_index[i].index] == value_) return pim_index[i].key; return default_;}
PIVector<Key> keys() const {
//! \~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);
const ssize_t i = _find(pair.first, f);
if (f) {
_value(i) = pair.second;
} else {
pim_content.push_back(pair.second);
pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1));
}
return *this;
}
inline PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
bool f(false);
Key k(std::move(pair.first));
const ssize_t i = _find(k, f);
if (f) {
_value(i) = std::move(pair.second);
} else {
pim_content.push_back(std::move(pair.second));
pim_index.insert(i, MapIndex(k, pim_content.size() - 1));
}
return *this;
}
//! \~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);
const ssize_t i = _find(key, f);
if (!f) return default_;
return _value(i);
}
//! \~english Returns an array of values of all elements
//! \~russian Возвращает массив значений всех эелметнов
inline PIVector<T> values() const { return pim_content; }
//! \~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) {
const auto & mi(pim_index[i]);
if (pim_content[mi.index] == value) {
return mi.key;
}
}
return default_;
}
//! \~english Returns an array of keys of all elements
//! \~russian Возвращает массив ключей всех элементов
inline PIVector<Key> keys() const {
PIVector<Key> ret;
for (int i = 0; i < pim_index.size_s(); ++i)
ret.reserve(pim_index.size());
for (int i = 0; i < pim_index.size_s(); ++i) {
ret << pim_index[i].key;
}
return ret;
}
void dump() {
piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:";
for (size_t i = 0; i < pim_content.size(); ++i)
piCout << PICoutManipulators::Tab << i << ":" << pim_content[i];
piCout << "index:";
for (size_t i = 0; i < pim_index.size(); ++i)
piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
//! \~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) {
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>
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());
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
ret.insert(f(mi.key, pim_content[mi.index]));
}
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>
inline PIVector<ST> map(std::function<ST(const Key & key, const T & value)> f) const {
PIVector<ST> ret;
ret.reserve(size());
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
ret << f(mi.key, pim_content[mi.index]);
}
return ret;
}
//! \~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 {
MapIndex(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) {}
Key key;
size_t index;
bool operator ==(const MapIndex & s) const {return key == s.key;}
bool operator !=(const MapIndex & s) const {return key != s.key;}
bool operator <(const MapIndex & s) const {return key < s.key;}
bool operator >(const MapIndex & s) const {return key > s.key;}
bool operator==(const MapIndex & s) const { return key == s.key; }
bool operator!=(const MapIndex & s) const { return key != s.key; }
bool operator<(const MapIndex & s) const { return key < s.key; }
bool operator>(const MapIndex & s) const { return key > s.key; }
};
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
ssize_t mid;
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
PIVector<T> pim_content;
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) {
mid = (first + last) / 2;
if (key > pim_index[mid].key) first = mid + 1;
else if (key < pim_index[mid].key) last = mid - 1;
else {found = true; return mid;}
if (key > pim_index[mid].key)
first = mid + 1;
else if (key < pim_index[mid].key)
last = mid - 1;
else {
found = true;
return mid;
}
}
found = false;
return first;
}
void _sort() {piQuickSort<MapIndex>(pim_index.data(), pim_index.size_s() - 1);}
ssize_t _find(const Key & k, bool & found) const {
inline ssize_t _find(const Key & k, bool & found) const {
if (pim_index.isEmpty()) {
found = false;
return 0;
}
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) {
//if (index >= pim_index.size()) return;
size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
inline void _remove(ssize_t index) {
const size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
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) {
pim_index[i].index = ci;
break;
}
}
piSwap<T>(pim_content[ci], pim_content.back());
pim_content.resize(pim_index.size());
}
const value_type _pair(ssize_t index) const {
if (index < 0 || index >= pim_index.size_s())
return value_type();
//piCout << "_pair" << index << pim_index[index].index;
return value_type(pim_index[index].key, pim_content[pim_index[index].index]);
inline const value_type _pair(ssize_t index) const {
if (index < 0 || index >= pim_index.size_s()) return value_type();
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;}
T & _value(ssize_t index) {return pim_content[pim_index[index].index];}
PIVector<T> pim_content;
PIDeque<MapIndex> pim_index;
inline Key & _key(ssize_t index) { return pim_index[index].key; }
inline const Key & _key(ssize_t index) const { return pim_index[index].key; }
inline T & _value(ssize_t index) { return pim_content[pim_index[index].index]; }
inline const T & _value(ssize_t index) const { return pim_content[pim_index[index].index]; }
};
template <typename Key, typename T>
class PIMapIterator {
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorConst
//! \brief
//! \~english Java-style iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial access keys and values in PIMap with read only permitions.
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря только для чтения.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
//! \~
//! \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
template<typename Key, typename T>
class PIMapIteratorConst {
typedef PIMap<Key, T> MapType;
public:
PIMapIterator(const PIMap<Key, T> & map, bool reverse = false): m(map), pos(-1), rev(reverse) {
if (rev) pos = m.size_s();
}
const Key & key() const {return const_cast<MapType & >(m)._key(pos);}
const T & value() const {return const_cast<MapType & >(m)._value(pos);}
T & valueRef() const {return const_cast<MapType & >(m)._value(pos);}
inline bool hasNext() const {
if (rev) {
return pos > 0;
} else {
return pos < (m.size_s() - 1);
}
return false;
}
inline PIMapIteratorConst(const PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline const T & value() const { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos < (m.size_s() - 1); }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
if (rev) {
--pos;
return pos >= 0;
} else {
++pos;
return pos < m.size_s();
}
return false;
}
inline void reset() {
if (rev) {
pos = m.size_s();
} else {
pos = -1;
}
++pos;
return pos < m.size_s();
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = -1; }
private:
const MapType & m;
ssize_t pos;
bool rev;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorConstReverse
//! \brief
//! \~english Java-style reverse iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial reverse access keys and values in PIMap with read only permitions.
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке только для чтения.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeReverseIterator();
//! while (it.next()) {
//! piCout << it.key() << it.value();
//! }
//! // 4 four
//! // 2 two
//! // 1 one
//! \endcode
template<typename Key, typename T>
class PIMapIteratorConstReverse {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorConstReverse(const PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline const T & value() const { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos > 0; }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
--pos;
return pos >= 0;
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = m.size_s(); }
private:
const MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIterator
//! \brief
//! \~english Java-style iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial access keys and values in PIMap with write permitions.
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря с доступом на запись.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeIterator();
//! while (it.next()) {
//! it.value().append("_!");
//! piCout << it.key() << it.value();
//! }
//! // 1 one_!
//! // 2 two_!
//! // 4 four_!
//! \endcode
template<typename Key, typename T>
class PIMapIterator {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline T & value() { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos < (m.size_s() - 1); }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
++pos;
return pos < m.size_s();
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = -1; }
private:
MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorReverse
//! \brief
//! \~english Java-style reverse iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial reverse access keys and values in PIMap with write permitions.
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке с доступом на запись.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeReverseIterator();
//! while (it.next()) {
//! it.value().append("_!");
//! piCout << it.key() << it.value();
//! }
//! // 4 four_!
//! // 2 two_!
//! // 1 one_!
//! \endcode
template<typename Key, typename T>
class PIMapIteratorReverse {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline T & value() { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos > 0; }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
--pos;
return pos >= 0;
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = m.size_s(); }
private:
MapType & m;
ssize_t pos;
};
#ifdef PIP_STD_IOSTREAM
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename Key, typename Type>
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
inline std::ostream & operator<<(std::ostream & s, const PIMap<Key, Type> & v) {
s << "{";
bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first)
s << ", ";
if (!first) s << ", ";
first = false;
s << i->first << ": " << i->second;
s << i.key() << ": " << i.value();
}
s << "}";
return s;
}
#endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename Key, typename Type>
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
inline PICout operator<<(PICout s, const PIMap<Key, Type> & v) {
s.space();
s.setControl(0, true);
s.saveAndSetControls(0);
s << "{";
bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first)
s << ", ";
if (!first) s << ", ";
first = false;
s << i->first << ": " << i->second;
s << i.key() << ": " << i.value();
}
s << "}";
s.restoreControl();
s.restoreControls();
return s;
}
template<typename Key, typename Type> inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
template<typename Key, typename Type>
inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {
f.swap(s);
}
#endif // PIMAP_H

View File

@@ -1,55 +1,136 @@
/*! @file pipair.h
* @brief pair
*
* This file declare PIPair
*/
//! \addtogroup Containers
//! \{
//! \file pipair.h
//! \brief
//! \~english Declares \a PIPair
//! \~russian Объявление \a PIPair
//! \~\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
pair
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
pair
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 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.
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/>.
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 PIPAIR_H
#define PIPAIR_H
#include "pibase.h"
#include "picout.h"
class PICout;
//! \addtogroup Containers
//! \{
//! \class PIPair
//! \brief
//! \~english Class template that provides a way to store two heterogeneous objects as a single unit.
//! \~russian Класс, который позволяет хранить два разнородных объекта как единое целое.
//! \~\}
//! \~\sa \a PIMap
template<typename Type0, typename Type1>
class PIPair {
public:
PIPair() {first = Type0(); second = Type1();}
PIPair(const Type0 & value0, const Type1 & value1) {first = value0; second = value1;}
//! \~english Constructs an empty PIPair.
//! \~russian Создает пустой PIPair.
PIPair(): first(), second() {}
//! \~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).
explicit PIPair(std::tuple<Type0, Type1> tuple) {
first = std::get<0>(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`.
//! \~russian Создает PIPair из `value0` и `value1`.
PIPair(const Type0 & value0, const Type1 & value1) {
first = value0;
second = value1;
}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
PIPair(Type0 && value0, Type1 && value1) {
first = std::move(value0);
second = std::move(value1);
}
//! \~english First element.
//! \~russian Первый элемент.
Type0 first;
//! \~english Second element.
//! \~russian Второй элемент.
Type1 second;
};
//! \~english Compare operator with PIPair.
//! \~russian Оператор сравнения с PIPair.
template<typename Type0, typename Type1>
inline bool operator <(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return value0.first < value1.first;}
inline bool operator==(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {
return (value0.first == value1.first) && (value0.second == value1.second);
}
//! \~english Compare operator with PIPair.
//! \~russian Оператор сравнения с PIPair.
template<typename Type0, typename Type1>
inline bool operator ==(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return (value0.first == value1.first) && (value0.second == value1.second);}
template<typename Type0, typename Type1>
inline bool operator !=(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {return (value0.first != value1.first) || (value0.second != value1.second);}
inline bool operator!=(const PIPair<Type0, Type1> & value0, const PIPair<Type0, Type1> & value1) {
return (value0.first != value1.first) || (value0.second != value1.second);
}
#ifdef PIP_STD_IOSTREAM
template<typename Type0, typename Type1>
inline std::ostream & operator <<(std::ostream & s, const PIPair<Type0, Type1> & v) {s << "(" << v.first << ", " << v.second << ")"; return s;}
inline std::ostream & operator<<(std::ostream & s, const PIPair<Type0, Type1> & v) {
s << "(" << v.first << ", " << v.second << ")";
return s;
}
#endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename Type0, typename Type1>
inline PICout operator <<(PICout s, const PIPair<Type0, Type1> & v) {s.space(); s.setControl(0, true); s << "(" << v.first << ", " << v.second << ")"; s.restoreControl(); return s;}
inline PICout operator<<(PICout s, const PIPair<Type0, Type1> & v) {
s.space();
s.saveAndSetControls(0);
s << "(" << v.first << ", " << v.second << ")";
s.restoreControls();
return s;
}
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
//! \~russian Создает \a PIPair выводя типы из аргументов.
//! \sa \a createPIPair()
template<class T1, class T2>
PIPair<T1, T2> createPIPair(T1 f, T2 s) {
return PIPair<T1, T2>(std::move(f), std::move(s));
}
#endif // PIPAIR_H

View File

@@ -1,25 +1,34 @@
/*! @file pideque.h
* @brief Queue container
*
* This file declare PIQueue
*/
//! \addtogroup Containers
//! \{
//! \file piqueue.h
//! \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
Queue container
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Queue container
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 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.
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/>.
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 PIQUEUE_H
@@ -28,24 +37,82 @@
#include "pideque.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>
class PIQueue: public PIDeque<T> {
public:
//! \~english Constructs an empty array.
//! \~russian Создает пустой массив.
PIQueue() {}
virtual ~PIQueue() {}
PIDeque<T> & enqueue(const T & v) {PIDeque<T>::push_front(v); return *this;}
PIDeque<T> & enqueue(T && v) {PIDeque<T>::push_front(std::move(v)); return *this;}
T dequeue() {return PIDeque<T>::take_back();}
T & head() {return PIDeque<T>::back();}
const T & head() const {return PIDeque<T>::back();}
PIVector<T> toVector() {
PIVector<T> v;
v.reserve(PIDeque<T>::size());
for (uint i = 0; i < PIDeque<T>::size(); ++i)
v.push_back(PIDeque<T>::at(i));
return v;
//! \~english Puts an element on the queue.
//! \~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(); }
//! \~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(); }
const T & head() const { return PIDeque<T>::back(); }
//! \~english Tail element of the queue.
//! \~russian Хвостовой (нижний) элемент очереди.
//! \~\details
//! \~english Returns a reference to the tail element of the queue.
//! 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

View File

@@ -1,25 +1,25 @@
/*! @file piset.h
* @brief Set container
*
/*! \file piset.h
* \brief Set container
*
* This file declare PISet
*/
*/
/*
PIP - Platform Independent Primitives
Set container
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Set container
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 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.
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/>.
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 PISET_H
@@ -27,37 +27,131 @@
#include "pimap.h"
/*! @brief Set of any type
/*! \brief Set of any type
* \details This class used to store collection of unique elements
* of any type. You can only add values to set with \a operator<< or
* with function \a insert(). You can discover if value already in
* set with \a operator[] or with function \a find(). These function
* has logarithmic complexity.
*/
template <typename T>
template<typename T>
class PISet: public PIMap<T, uchar> {
typedef PIMap<T, uchar> _CSet;
public:
//! Contructs an empty set
PISet() {}
virtual ~PISet() {;}
//! 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"
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"
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"
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
PISet(const PIVector<T> & values) {
explicit PISet(const PIVector<T> & values) {
if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0);
@@ -65,7 +159,7 @@ public:
}
//! Contructs set from deque of elements
PISet(const PIDeque<T> & values) {
explicit PISet(const PIDeque<T> & values) {
if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0);
@@ -73,89 +167,129 @@ public:
}
typedef T key_type;
PISet<T> & operator <<(const T & t) {_CSet::insert(t, 0); 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;}
PISet<T> & operator<<(const T & t) {
_CSet::insert(t, 0);
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
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
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"
PISet<T> & unite(const PISet<T> & v) {
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
_CSet::insert(i->first, 0);
for (const auto & i: v)
_CSet::insert(i, 0);
return *this;
}
//! Subtract set with "v"
PISet<T> & subtract(const PISet<T> & v) {
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
_CSet::remove(i->first);
for (const auto & i: v)
_CSet::remove(i);
return *this;
}
//! Intersect set with "v"
PISet<T> & intersect(const PISet<T> & v) {
for (typename _CSet::iterator i = _CSet::begin(); i != _CSet::end(); ++i)
if (!v.contains(i.key())) {
_CSet::remove(i.key());
--i;
}
_CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); });
return *this;
}
//! Unite set with "v"
PISet<T> & operator +=(const PISet<T> & v) {return unite(v);}
PISet<T> & operator+=(const PISet<T> & v) { return unite(v); }
//! Unite set with "v"
PISet<T> & operator |=(const PISet<T> & v) {return unite(v);}
PISet<T> & operator|=(const PISet<T> & v) { return unite(v); }
//! Subtract set with "v"
PISet<T> & operator -=(const PISet<T> & v) {return subtract(v);}
PISet<T> & operator-=(const PISet<T> & v) { return subtract(v); }
//! Intersect set with "v"
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
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
PIVector<T> toVector() const {
PIVector<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
//! 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).first; 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
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 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;
}
//! \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;}
//! \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;
}
//! \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;}
//! \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;
}
//! \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;}
//! \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 Type>
inline PICout operator <<(PICout s, const PISet<Type> & v) {
inline PICout operator<<(PICout s, const PISet<Type> & v) {
s.space();
s.setControl(0, true);
s.saveAndSetControls(0);
s << "{";
bool first = true;
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first)
s << ", ";
for (const auto & i: v) {
if (!first) s << ", ";
first = false;
s << i->first;
s << i;
}
s << "}";
s.restoreControl();
s.restoreControls();
return s;
}

View File

@@ -1,49 +1,106 @@
/*! @file pistack.h
* @brief Stack container
*
* This file declare PIStack
*/
//! \addtogroup Containers
//! \{
//! \file pistack.h
//! \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
Stack container
Ivan Pelipenko peri4ko@yandex.ru
PIP - Platform Independent Primitives
Stack container
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 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.
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/>.
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 PISTACK_H
#define PISTACK_H
#include "pideque.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>
class PIStack: public PIVector<T> {
public:
PIStack() {;}
virtual ~PIStack() {;}
PIVector<T> & push(const T & v) {PIVector<T>::push_back(v); return *this;}
PIVector<T> & push(T && v) {PIVector<T>::push_back(std::move(v)); return *this;}
T pop() {return PIVector<T>::take_back();}
T & top() {return PIVector<T>::back();}
const T & top() const {return PIVector<T>::back();}
PIVector<T> toVector() {
PIVector<T> v;
v.reserve(PIVector<T>::size());
for (uint i = 0; i < PIVector<T>::size(); ++i)
v.push_back(PIVector<T>::at(i));
return v;
//! \~english Constructs an empty array.
//! \~russian Создает пустой массив.
PIStack() {}
//! \~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(); }
//! \~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(); }
const T & top() const { return PIVector<T>::back(); }
//! \~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

View File

@@ -1,170 +0,0 @@
/** \class PIVector
* @brief Dynamic array of any type
* \details This class used to store dynamic array of any
* type of data. In memory data stored linear. You can insert
* item in any place of remove some items from any place.
* For quick add elements this is stream operator <<.
* \fn PIVector::PIVector();
* Contructs an empty vector
* \fn PIVector::PIVector(size_t size, const T & value = T());
* @brief Contructs vector with size "size" filled elements "value"
* \details Example: \snippet picontainers.cpp PIVector::PIVector
* \fn PIVector::PIVector(std::initializer_list list);
* @brief Contructs vector from C++11 initializer list
* \details Example: \snippet picontainers.cpp PIVector::PIVector
* \fn const T & PIVector::at(size_t index) const;
* @brief Read-only access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::at_c
* \sa \a operator[]
* \fn T & PIVector::at(size_t index);
* @brief Full access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::at
* \sa \a operator[]
* \fn const T * PIVector::data(size_t index = 0) const;
* @brief Read-only pointer to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::data_c
* \fn T * PIVector::data(size_t index = 0);
* @brief Pointer to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::data
* \fn size_t PIVector::size() const;
* @brief Elements count
* \fn ssize_t PIVector::size_s() const;
* @brief Elements count
* \fn bool PIVector::isEmpty() const;
* @brief Return \c "true" if vector is empty, i.e. size = 0
* \fn bool PIVector::has(const T & t) const;
* \fn bool PIVector::contains(const T & v) const;
* @brief Return \c "true" if vector has at least one element equal "t"
* \fn int PIVector::etries(const T & t) const;
* @brief Return how many times element "t" appears in vector
* \fn ssize_t PIVector::indexOf(const T & t) const;
* @brief Return index of first element equal "t" or -1 if there is no such element
* \fn ssize_t PIVector::lastIndexOf(const T & t) const;
* @brief Return index of last element equal "t" or -1 if there is no such element
* \fn static int PIVector::compare_func(const T * t0, const T * t1);
* @brief Standard compare function for type "T". Return 0 if t0 = t1, -1 if t0 < t1 and 1 if t0 > t1.
* \fn void PIVector::resize(size_t size, const T & new_type = T());
* @brief Resize vector to size "size"
* \details Elements removed from end of vector if new size < old size, or added new elements = "new_type" if new size > old size.\n
* Example: \snippet picontainers.cpp PIVector::resize
* \sa \a size(), \a clear()
* \fn PIVector & PIVector::enlarge(size_t size);
* @brief Increase vector size with "size" elements
* \fn void PIVector::clear();
* @brief Clear vector. Equivalent to call <tt>"resize(0)"</tt>
* \fn PIVector & PIVector::sort(CompareFunc compare = compare_func);
* @brief Sort vector using quick sort algorithm and standard compare function
* \details Example: \snippet picontainers.cpp PIVector::sort_0
* With custom compare function: \snippet picontainers.cpp PIVector::sort_1
* \fn PIVector & PIVector::fill(const T & t);
* @brief Fill vector with elements "t" leave size is unchanged and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::fill
* \fn PIVector & PIVector::assign(const T & t = T());
* @brief Synonym of \a fill(t)
* \fn PIVector & PIVector::assign(size_t new_size, const T & t);
* @brief Resize to "new_size", then fill with "t"
* \fn T & PIVector::back();
* @brief Last element of the vector
* \fn const T & PIVector::back() const;
* @brief Last element of the vector
* \fn T & PIVector::front();
* @brief First element of the vector
* \fn const T & PIVector::front() const;
* @brief First element of the vector
* \fn PIVector & PIVector::push_back(const T & t);
* @brief Add new element "t" at the end of vector and return reference to vector
* \fn PIVector & PIVector::push_front(const T & t);
* @brief Add new element "t" at the beginning of vector and return reference to vector
* \fn PIVector & PIVector::pop_back();
* @brief Remove one element from the end of vector and return reference to vector
* \fn PIVector & PIVector::pop_front();
* @brief Remove one element from the beginning of vector and return reference to vector
* \fn T PIVector::take_back();
* @brief Remove one element from the end of vector and return it
* \fn T PIVector::take_front();
* @brief Remove one element from the beginning of vector and return it
* \fn PIVector & PIVector::remove(size_t index);
* @brief Remove one element by index "index" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::remove_0
* \sa \a removeOne(), \a removeAll()
* \fn PIVector & PIVector::remove(size_t index, size_t count);
* @brief Remove "count" elements by first index "index" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::remove_1
* \sa \a removeOne(), \a removeAll()
* \fn PIVector & PIVector::removeOne(const T & v);
* @brief Remove no more than one element equal "v" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::removeOne
* \sa \a remove(), \a removeAll()
* \fn PIVector & PIVector::removeAll(const T & v);
* @brief Remove all elements equal "v" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::removeAll
* \sa \a remove(), \a removeOne()
* \fn PIVector & PIVector::insert(size_t pos, const T & t);
* @brief Insert element "t" after index "pos" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::insert_0
* \fn PIVector & PIVector::insert(size_t pos, const PIVector & t);
* @brief Insert other vector "t" after index "pos" and return reference to vector
* \details Example: \snippet picontainers.cpp PIVector::insert_1
* \fn T & PIVector::operator [](size_t index);
* @brief Full access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::()
* \sa \a at()
* \fn const T & PIVector::operator [](size_t index) const;
* @brief Read-only access to element by index "index"
* \details Example: \snippet picontainers.cpp PIVector::()_c
* \sa \a at()
* \fn PIVector & PIVector::operator <<(const T & t);
* @brief Add new element "t" at the end of vector and return reference to vector
* \fn PIVector & PIVector::operator <<(const PIVector & t);
* @brief Add vector "t" at the end of vector and return reference to vector
* \fn bool PIVector::operator ==(const PIVector & t);
* @brief Compare with vector "t"
* \fn bool PIVector::operator !=(const PIVector & t);
* @brief Compare with vector "t"
* */

View File

@@ -1,25 +1,34 @@
/*! @file pivector.h
* @brief Dynamic array of any type
*
* This file declares PIVector
*/
//! \addtogroup Containers
//! \{
//! \file pivector.h
//! \brief
//! \~english Declares \a PIVector
//! \~russian Объявление \a PIVector
//! \~\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
Dynamic array of any type
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
Sequence linear container aka dynamic size array of any type
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 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.
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/>.
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 PIVECTOR_H
@@ -28,609 +37,2585 @@
#include "picontainers.h"
template <typename T>
//! \addtogroup Containers
//! \{
//! \class PIVector
//! \brief
//! \~english Sequence linear container - dynamic size array of any type.
//! \~russian Последовательный контейнер с линейной памятью - динамический массив любого типа.
//! \~\}
//! \details
//! \~english
//! The elements are stored contiguously,
//! which means that elements can be accessed not only through iterators,
//! but also using offsets to regular pointers to elements.
//! This means that a pointer to an element of a PIVector may be passed to any function
//! that expects a pointer to an element of an array.
//! To add elements you can use functions \a append() and \a insert(),
//! to remove elements you can use functions \a remove() and \a removeOne(), \a removeWhere().
//! Change size by function \a resize() and \a assign().
//! Items in an array are numbered, starting from zero.
//! This number is called the item's index.
//! So the first item has index 0, the last has index `size() - 1`.
//! A set of various convenient functions is also available for the array,
//! for example: \a indexOf(), \a contains(), \a entries(), \a isEmpty(), \a isNotEmpty(),
//! \a every(), \a any(), \a forEach(), \a indexWhere(), \a getRange(), \a sort(),
//! \a map(), \a reduce(), \a filter(), \a flatten(), \a reshape() and others.
//!
//! The storage of the PIVector is handled automatically,
//! being expanded as needed.
//! PIVector usually occupy more space than static arrays,
//! because more memory is allocated to handle future growth.
//! This way a PIVector does not need to reallocate each time an element is inserted,
//! but only when the additional memory is exhausted.
//! The total amount of allocated memory can be queried using \a capacity() function.
//! Reallocations are usually costly operations in terms of performance.
//! The \a reserve() function can be used to eliminate reallocations
//! if the number of elements is known beforehand.
//!
//! The complexity (efficiency) of common operations on PIVector is as follows:
//! - Random access - constant O(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 O(n)
//!
//! \~russian
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
//! но и с помощью смещений для обычных указателей на элементы.
//! Это означает, что указатель на элемент PIVector может передаваться в любую функцию,
//! ожидающую указатель на элемент массива.
//! Добавить элементы можно с помощью функции \a append() или \a insert(),
//! а удалить с помощью \a remove() или \a removeOne(), \a removeWhere().
//! Изменить размер можно функцией \a resize() или \a assign().
//! Массив индексируется с нуля:
//! первый элемент массива имеет индекс, равный `0`,
//! а индекс последнего элемента равен `size() - 1`.
//! Также для массива доступен набор различных удобных функций,
//! например: \a indexOf(), \a contains(), \a entries(), \a isEmpty(), \a isNotEmpty(),
//! \a every(), \a any(), \a forEach(), \a indexWhere(), \a getRange(), \a sort(),
//! \a map(), \a reduce(), \a filter(), \a flatten(), \a reshape() и другие.
//!
//! Память PIVector обрабатывается автоматически,
//! расширяясь по мере необходимости.
//! Векторы обычно занимают больше места, чем статические массивы,
//! поскольку больше памяти выделяется для обработки будущего роста.
//! Таким образом, память для PIVector требуется выделять
//! не при каждой вставке элемента,
//! а только после исчерпания дополнительной памяти.
//! Общий объём выделенной памяти можно получить с помощью функции \a capacity().
//!
//! Выделение памяти обычно является дорогостоящей операцией
//! с точки зрения производительности.
//! Функцию \a reserve() можно использовать для исключения выделения памяти,
//! если количество элементов известно заранее.
//!
//! Сложность (эффективность) обычных операций над PIVector следующая:
//! - Произвольный доступ — постоянная O(1)
//! - Вставка и удаление элементов в конце — амортизированная постоянная O(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n)
//!
//! \~\sa \a PIDeque, \a PIMap
template<typename T>
class PIVector {
public:
inline PIVector(): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
inline PIVector(const T * data, size_t size): piv_data(0), piv_size(0), piv_rsize(0) {
typedef bool (*CompareFunc)(const T &, const T &);
typedef T value_type;
typedef T * pointer;
typedef const T * const_pointer;
typedef T & reference;
typedef const T & const_reference;
typedef size_t size_type;
//! \~english Constructs an empty array.
//! \~russian Создает пустой массив.
inline PIVector() { PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) }
//! \~english Contructs array from raw `data`.
//! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`.
inline PIVector(const T * data, size_t size) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(size);
newT(piv_data, data, piv_size);
}
inline PIVector(const PIVector<T> & other): piv_data(0), piv_size(0), piv_rsize(0) {
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIVector(const PIVector<T> & v) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(other.piv_size);
newT(piv_data, other.piv_data, piv_size);
alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size);
}
inline PIVector(std::initializer_list<T> init_list): piv_data(0), piv_size(0), piv_rsize(0) {
//! \~english Contructs array from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Создает массив из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\details
//! \~\code
//! PIVector <int> v{1,2,3};
//! piCout << v; // {1, 2, 3}
//! \endcode
inline PIVector(std::initializer_list<T> init_list) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(init_list.size());
newT(piv_data, init_list.begin(), init_list.size());
}
inline PIVector(size_t piv_size, const T & f = T()): piv_data(0), piv_size(0), piv_rsize(0) {
//! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `e`.
inline explicit PIVector(size_t size, const T & e = T()) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
expand(size, e);
}
inline PIVector(size_t piv_size, std::function<T(size_t)> f): piv_data(0), piv_size(0), piv_rsize(0) {
//! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
//! \~russian Создает массив из `size` элементов созданных функцией `f(size_t i)`.
//! \~\details
//! \~english Can use
//! [Lambda expressions](https://en.cppreference.com/w/cpp/language/lambda)
//! as constructor argument.
//! \~russian Позволяет передавать
//! [Лямбда-выражения](https://ru.cppreference.com/w/cpp/language/lambda)
//! для создания элементов в конструкторе.
//! \~\code
//! PIVector <int> v(5, [](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4, 6, 8}
//! \endcode
inline PIVector(size_t size, std::function<T(size_t i)> f) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
expand(size, f);
}
inline PIVector(PIVector<T> && other): piv_data(other.piv_data), piv_size(other.piv_size), piv_rsize(other.piv_rsize) {
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIVector(PIVector<T> && v) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
other._reset();
piv_data = v.piv_data;
piv_size = v.piv_size;
piv_rsize = v.piv_rsize;
v._reset();
}
inline virtual ~PIVector() {
inline ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
deleteT(piv_data, piv_size);
dealloc();
_reset();
}
inline PIVector<T> & operator =(const PIVector<T> & other) {
if (this == &other) return *this;
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIVector<T> & operator=(const PIVector<T> & v) {
if (this == &v) return *this;
clear();
deleteT(piv_data, piv_size);
alloc(other.piv_size);
newT(piv_data, other.piv_data, piv_size);
alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size);
return *this;
}
inline PIVector<T> & operator =(PIVector<T> && other) {
swap(other);
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIVector<T> & operator=(PIVector<T> && v) {
swap(v);
return *this;
}
typedef T value_type;
enum ReshapeOrder {
byRow,
byColumn
};
class iterator {
friend class PIVector<T>;
private:
inline iterator(PIVector<T> * v, size_t p): parent(v), pos(p) {}
inline iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent;
size_t pos;
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 iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {++pos;}
inline void operator ++(int) {++pos;}
inline void operator --() {--pos;}
inline void operator --(int) {--pos;}
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
inline T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline iterator & operator++() {
++pos;
return *this;
}
inline iterator operator++(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline iterator & operator--() {
--pos;
return *this;
}
inline iterator operator--(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline iterator & operator+=(const iterator & it) {
pos += it.pos;
return *this;
}
inline iterator & operator+=(size_t p) {
pos += p;
return *this;
}
inline iterator & operator-=(const iterator & it) {
pos -= it.pos;
return *this;
}
inline iterator & operator-=(size_t p) {
pos -= p;
return *this;
}
friend inline iterator operator-(size_t p, const iterator & it) { return it - p; }
friend inline iterator operator-(const iterator & it, size_t p) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const iterator & it1, const iterator & it2) { return it1.pos - it2.pos; }
friend inline iterator operator+(size_t p, const iterator & it) { return it + p; }
friend inline iterator operator+(const iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
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) { 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) { return it1.pos >= it2.pos; }
};
class const_iterator {
friend class PIVector<T>;
private:
inline const_iterator(const PIVector<T> * v, size_t p): parent(v), pos(p) {}
inline const_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
const PIVector<T> * parent;
size_t pos;
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)[pos];}
inline void operator ++() {++pos;}
inline void operator ++(int) {++pos;}
inline void operator --() {--pos;}
inline void operator --(int) {--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 const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
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; }
};
class reverse_iterator {
friend class PIVector<T>;
private:
inline reverse_iterator(PIVector<T> * v, size_t p): parent(v), pos(p) {}
inline reverse_iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent;
size_t pos;
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 reverse_iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;}
inline void operator ++(int) {--pos;}
inline void operator --() {++pos;}
inline void operator --(int) {++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 T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline reverse_iterator & operator++() {
--pos;
return *this;
}
inline reverse_iterator operator++(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline reverse_iterator & operator--() {
++pos;
return *this;
}
inline reverse_iterator operator--(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline reverse_iterator & operator+=(const reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline reverse_iterator & operator+=(size_t p) {
pos -= p;
return *this;
}
inline reverse_iterator & operator-=(const reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline reverse_iterator & operator-=(size_t p) {
pos += p;
return *this;
}
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) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const reverse_iterator & it1, const reverse_iterator & it2) { 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+(const reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
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) { 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) { return it1.pos >= it2.pos; }
};
class const_reverse_iterator {
friend class PIVector<T>;
private:
inline const_reverse_iterator(const PIVector<T> * v, size_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;
size_t pos;
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_reverse_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;}
inline void operator ++(int) {--pos;}
inline void operator --() {++pos;}
inline void operator --(int) {++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 const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline const_reverse_iterator & operator++() {
--pos;
return *this;
}
inline const_reverse_iterator operator++(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline const_reverse_iterator & operator--() {
++pos;
return *this;
}
inline const_reverse_iterator operator--(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline const_reverse_iterator & operator+=(const const_reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_reverse_iterator & operator+=(size_t p) {
pos -= p;
return *this;
}
inline const_reverse_iterator & operator-=(const const_reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline const_reverse_iterator & operator-=(size_t p) {
pos += p;
return *this;
}
friend inline const_reverse_iterator operator-(size_t p, const const_reverse_iterator & it) { return it - p; }
friend inline const_reverse_iterator operator-(const const_reverse_iterator & it, size_t p) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const const_reverse_iterator & it1, const const_reverse_iterator & it2) {
return it2.pos - it1.pos;
}
friend inline const_reverse_iterator operator+(size_t p, const const_reverse_iterator & it) { return it + p; }
friend inline const_reverse_iterator operator+(const const_reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
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) { 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) { return it1.pos >= it2.pos; }
};
inline iterator begin() {return iterator(this, 0);}
inline iterator end() {return iterator(this, piv_size);}
inline const_iterator begin() const {return const_iterator(this, 0);}
inline const_iterator end() const {return const_iterator(this, piv_size);}
inline reverse_iterator rbegin() {return reverse_iterator(this, piv_size - 1);}
inline reverse_iterator rend() {return reverse_iterator(this, -1);}
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, piv_size - 1);}
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
//! \~english Iterator to the first element.
//! \~russian Итератор на первый элемент.
//! \~\details ![begin, end](doc/images/pivector_begin.png)
//!
//! \~english If the array is empty, the returned iterator is equal to \a end().
//! \~russian Если массив пустой, возвращаемый итератор будет равен \a end().
//! \~\return \ref stl_iterators
//! \~\sa \a end(), \a rbegin(), \a rend()
inline iterator begin() { return iterator(this, 0); }
inline size_t size() const {return piv_size;}
inline ssize_t size_s() const {return piv_size;}
inline size_t length() const {return piv_size;}
inline size_t capacity() const {return piv_rsize;}
inline bool isEmpty() const {return (piv_size == 0);}
//! \~english Iterator to the element following the last element.
//! \~russian Итератор на элемент, следующий за последним элементом.
//! \~\details ![begin, end](doc/images/pivector_begin.png)
//!
//! \~english This element acts as a placeholder;
//! attempting to access it results in undefined behavior.
//! \~russian Этот элемент существует лишь условно,
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\return \ref stl_iterators
//! \~\sa \a begin(), \a rbegin(), \a rend()
inline iterator end() { return iterator(this, piv_size); }
inline T & operator [](size_t index) {return piv_data[index];}
inline const T & operator [](size_t index) const {return piv_data[index];}
inline const T & at(size_t index) const {return piv_data[index];}
inline T & back() {return piv_data[piv_size - 1];}
inline const T & back() const {return piv_data[piv_size - 1];}
inline T & front() {return piv_data[0];}
inline const T & front() const {return piv_data[0];}
inline bool operator ==(const PIVector<T> & t) const {
if (piv_size != t.piv_size)
return false;
for (size_t i = 0; i < piv_size; ++i)
if (t[i] != piv_data[i])
return false;
return true;
}
inline bool operator !=(const PIVector<T> & t) const {return !(*this == t);}
inline bool contains(const T & v) const {
for (size_t i = 0; i < piv_size; ++i)
if (v == piv_data[i])
return true;
inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, piv_size); }
//! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
//! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png)
//!
//! \~english It corresponds to the last element of the non-reversed array.
//! If the array is empty, the returned iterator is equal to \a rend().
//! \~russian Итератор для прохода массива в обратном порядке.
//! Указывает на последний элемент.
//! Если массив пустой, то совпадает с итератором \a rend().
//! \~\return \ref stl_iterators
//! \~\sa \a rend(), \a begin(), \a end()
inline reverse_iterator rbegin() { return reverse_iterator(this, piv_size - 1); }
//! \~english Returns a reverse iterator to the element
//! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент, следующий за последним элементом.
//! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png)
//!
//! \~english It corresponds to the element preceding the first element of the non-reversed array.
//! This element acts as a placeholder, attempting to access it results in undefined behavior.
//! \~russian Итератор для прохода массива в обратном порядке.
//! Указывает на элемент, предшествующий первому элементу.
//! Этот элемент существует лишь условно,
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\return \ref stl_iterators
//! \~\sa \a rbegin(), \a begin(), \a end()
inline reverse_iterator rend() { return reverse_iterator(this, -1); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(this, piv_size - 1); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(this, -1); }
//! \~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 piv_size; }
//! \~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 ssize_t size_s() const { return piv_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 piv_size; }
//! \~english Number of elements that the container has currently allocated space for.
//! \~russian Количество элементов, для которого сейчас выделена память массивом.
//! \~\details
//! \~english To find out the actual number of items, use the function \a size().
//! \~russian Чтобы узнать фактическое количество элементов используйте функцию \a size().
//! \~\sa \a reserve(), \a size(), \a size_s()
inline size_t capacity() const { return piv_rsize; }
//! \~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 (piv_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 (piv_size > 0); }
//! \~english Tests whether at least one element in the array
//! passes the test implemented by the provided function `test`.
//! \~russian Проверяет, удовлетворяет ли какой-либо элемент массива условию,
//! заданному в передаваемой функции `test`.
//! \~\return
//! \~english **true** if, in the array,
//! it finds an element for which the provided function returns **true**;
//! otherwise it returns **false**. Always returns **false** if is empty.
//! \~russian **true** если хотя бы для одного элемента
//! передаваемая функция возвращает **true**, в остальных случаях **false**.
//! Метод возвращает **false** при любом условии для пустого массива.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 8, 9};
//! piCout << v.any([](int e){return e % 2 == 0;}); // true
//! piCout << v.any([](int e){return e == 3;}); // false
//! \endcode
//! \~\sa \a every(), \a contains(), \a entries(), \a forEach()
inline bool any(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < piv_size; ++i) {
if (test(piv_data[i])) return true;
}
return false;
}
inline int etries(const T & v) const {
//! \~english Tests whether all elements in the array passes the test
//! implemented by the provided function `test`.
//! \~russian Проверяет, удовлетворяют ли все элементы массива условию,
//! заданному в передаваемой функции `test`.
//! \~\return
//! \~english **true** if, in the array,
//! it finds an element for which the provided function returns **true**;
//! otherwise it returns **false**. Always returns **true** if is empty.
//! \~russian **true** если для всех элементов передаваемая функция возвращает **true**,
//! в остальных случаях **false**.
//! Метод возвращает **true** при любом условии для пустого массива.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 8, 9};
//! piCout << v.every([](int e){return e % 2 == 0;}); // false
//! piCout << v.every([](int e){return e > 0;}); // true
//! \endcode
//! \~\sa \a any(), \a contains(), \a entries(), \a forEach()
inline bool every(std::function<bool(const T & e)> test) const {
for (size_t i = 0; i < piv_size; ++i) {
if (!test(piv_data[i])) return false;
}
return true;
}
//! \~english Full access to element by `index`.
//! \~russian Полный доступ к элементу по индексу `index`.
//! \~\details
//! \~english Element index starts from `0`.
//! Element index must be in range from `0` to `size()-1`.
//! Otherwise will be undefined behavior.
//! \~russian Индекс элемента считается от `0`.
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! \~\code
//! PIVector<int> v{1, 2, 8, 9};
//! piCout << v[2]; // 8
//! v[2] = 5;
//! piCout << v; // {1, 2, 5, 9}
//! \endcode
//! \~\sa \a at()
inline T & operator[](size_t index) { return piv_data[index]; }
inline const T & operator[](size_t index) const { return piv_data[index]; }
//! \~english Read only access to element by `index`.
//! \~russian Доступ исключительно на чтение к элементу по индексу `index`.
//! \~\details
//! \~english Element index starts from `0`.
//! Element index must be in range from `0` to `size()-1`.
//! Otherwise will be undefined behavior.
//! \~russian Индекс элемента считается от `0`.
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
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.
//! \~russian Последний элемент массива.
//! \~\details
//! \~english Returns a reference to the last item in the array.
//! This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Возвращает ссылку на последний элемент в массиве.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline T & back() { return piv_data[piv_size - 1]; }
inline const T & back() const { return piv_data[piv_size - 1]; }
//! \~english Last element.
//! \~russian Первый элемент массива.
//! \~\details
//! \~english Returns a reference to the last item in the array.
//! This function assumes that the array isn't empty.
//! Otherwise will be undefined behavior.
//! \~russian Возвращает ссылку на пенрвый элемент в массиве.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline T & front() { return piv_data[0]; }
inline const T & front() const { return piv_data[0]; }
//! \~english Compare operator with array `v`.
//! \~russian Оператор сравнения с массивом `v`.
inline bool operator==(const PIVector<T> & v) const {
if (piv_size != v.piv_size) return false;
for (size_t i = 0; i < piv_size; ++i) {
if (v[i] != piv_data[i]) return false;
}
return true;
}
//! \~english Compare operator with array `v`.
//! \~russian Оператор сравнения с массивом `v`.
inline bool operator!=(const PIVector<T> & v) const { return !(*this == v); }
//! \~english Tests if element `e` exists in the array.
//! \~russian Проверяет наличие элемента `e` в массиве.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! **false** is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<int> v{1, 2, 3, 4};
//! piCout << v.contains(3); // true
//! piCout << v.contains(5); // false
//! piCout << v.contains(3, 3); // false
//! piCout << v.contains(3, -2); // true
//! piCout << v.contains(3, -99); // true
//! \endcode
//! \~\return
//! \~english **true** if the array contains an occurrence of element `e`,
//! otherwise it returns **false**.
//! \~russian **true** если элемент `e` присутствует в массиве,
//! в остальных случаях **false**.
//! \~\sa \a every(), \a any(), \a entries(), \a forEach()
inline bool contains(const T & e, ssize_t start = 0) const {
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) return true;
}
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.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! 0 is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<int> v{2, 2, 4, 2, 6};
//! piCout << v.entries(2); // 3
//! piCout << v.entries(2, 2); // 1
//! piCout << v.entries(2, -4); // 2
//! \endcode
//! \~\sa \a every(), \a any(), \a contains(), \a forEach(), \a indexOf()
inline int entries(const T & e, ssize_t start = 0) const {
int ec = 0;
for (size_t i = 0; i < piv_size; ++i)
if (v == piv_data[i]) ++ec;
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) ++ec;
}
return ec;
}
inline ssize_t indexOf(const T & v) const {
for (size_t i = 0; i < piv_size; ++i)
if (v == piv_data[i])
return i;
return -1;
//! \~english Count elements in the array passes the test implemented by the provided function `test`.
//! \~russian Подсчитывает количество элементов в массиве,
//! проходящих по условию, заданному в передаваемой функции `test`.
//! \~\details
//! \~english Overloaded function.
//! Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! 0 is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Перегруженная функция.
//! Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\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 {
int ec = 0;
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (size_t i = start; i < piv_size; ++i) {
if (test(piv_data[i])) ++ec;
}
return ec;
}
inline ssize_t lastIndexOf(const T & v) const {
for (ssize_t i = piv_size - 1; i >= 0; --i)
if (v == piv_data[i])
return i;
//! \~english Returns the first index at which a given element `e`
//! can be found in the array, or `-1` if it is not present.
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
//! может быть найден в массиве или `-1`, если такого индекса нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! `-1` is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<int> v{2, 5, 9};
//! piCout << v.indexOf(2); // 0
//! piCout << v.indexOf(7); // -1
//! piCout << v.indexOf(9, 2); // 2
//! piCout << v.indexOf(2, -1); // -1
//! piCout << v.indexOf(2, -3); // 0
//! \endcode
//! \~\sa \a indexWhere(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) return i;
}
return -1;
}
inline T * data(size_t index = 0) {return &(piv_data[index]);}
inline const T * data(size_t index = 0) const {return &(piv_data[index]);}
//! \~english Returns the first index passes the test implemented by the provided function `test`,
//! or `-1` if it is not present.
//! can be found in the array, or `-1` if it is not present.
//! \~russian Возвращает первый индекс элемента проходящего по условию,
//! заданному в передаваемой функции `test`, или `-1`, если таких элементов нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array at which to begin searching.
//! If the index is greater than or equal to the array's size,
//! `-1` is returned, which means the array will not be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Note: if the provided index is negative,
//! the array is still searched from front to back.
//! Default: 0 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
//! Если индекс больше или равен длине массива,
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<PIString> v{"do", "re", "mi", "re"};
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('r');}); // 1
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('r');}, 2); // 3
//! piCout << v.indexWhere([](const PIString & s){return s.startsWith('k');}); // -1
//! \endcode
//! \~\sa \a indexOf(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
inline ssize_t indexWhere(std::function<bool(const T & e)> test, ssize_t start = 0) const {
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (size_t i = start; i < piv_size; ++i) {
if (test(piv_data[i])) return i;
}
return -1;
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
//! \~english Returns the last index at which a given element `e`
//! can be found in the array, or `-1` if it is not present.
//! \~russian Возвращает последний индекс, по которому данный элемент `e`
//! может быть найден в массиве или `-1`, если такого индекса нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array
//! at which to start searching backwards.
//! If the index is greater than or equal to the array's size,
//! causes the whole array to be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Therefore, if calculated index less than 0,
//! the array is not searched, and the method returns `-1`.
//! Note: if the provided index is negative,
//! the array is still searched from back to front.
//! Default: -1 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
//! \~\code
//! PIVector<int> v{2, 5, 9, 2};
//! piCout << v.lastIndexOf(2); // 3
//! piCout << v.lastIndexOf(7); // -1
//! piCout << v.lastIndexOf(2, 2); // 0
//! piCout << v.lastIndexOf(2, -3); // 0
//! piCout << v.lastIndexOf(2, -300); // -1
//! piCout << v.lastIndexOf(2, 300); // 3
//! \endcode
//! \~\sa \a indexOf(), \a indexWhere(), \a lastIndexWhere(), \a contains()
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start >= size_s()) start = piv_size - 1;
if (start < 0) start = piv_size + start;
for (ssize_t i = start; i >= 0; --i) {
if (e == piv_data[i]) return i;
}
return -1;
}
//! \~english Returns the last index passes the test implemented by the provided function `test`,
//! or `-1` if it is not present.
//! \~russian Возвращает последний индекс элемента проходящего по условию,
//! заданному в передаваемой функции `test`, или `-1`, если таких элементов нет.
//! \~\details
//! \~english Optional argument `start` - the position in this array
//! at which to start searching backwards.
//! If the index is greater than or equal to the array's size,
//! causes the whole array to be searched.
//! If the provided index value is a negative number,
//! it is taken as the offset from the end of the array.
//! Therefore, if calculated index less than 0,
//! the array is not searched, and the method returns `-1`.
//! Note: if the provided index is negative,
//! the array is still searched from back to front.
//! Default: -1 (entire array is searched).
//! \~russian Опциональный аргумент `start` указывает на индекс
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
//! \~\sa \a indexOf(), \a lastIndexOf(), \a indexWhere(), \a contains()
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
if (start >= size_s()) start = piv_size - 1;
if (start < 0) start = piv_size + start;
for (ssize_t i = start; i >= 0; --i) {
if (test(piv_data[i])) return i;
}
return -1;
}
//! \~english Pointer to array
//! \~russian Указатель на память массива
//! \~\details
//! \~english Optional argument `index` the position in this array,
//! where is pointer. Default: start of array.
//! \~russian Опциональный аргумент `index` указывает на индекс c которого брать указатель.
//! По умолчанию указывает на начало массива.
//! \~\code
//! PIVector<int> v{2, 5, 9, 2};
//! int a[2] = {12, 13};
//! memcpy(vec.data(1), a, 2 * sizeof(int));
//! piCout << v; // {2, 12, 13, 2}
//! \endcode
inline T * data(size_t index = 0) { return &(piv_data[index]); }
//! \~english Read only pointer to array
//! \~russian Указатель на память массива только для чтения.
//! \~\details
//! \~english The pointer can be used to access and modify the items in the array.
//! The pointer remains valid as long as the array isn't reallocated.
//! Optional argument `index` the position in this array,
//! where is pointer. Default: start of array.
//! \~russian Указатель можно использовать для доступа и изменения элементов в массиве.
//! Указатель остается действительным только до тех пор, пока массив не будет перераспределен.
//! Опциональный аргумент `index` указывает на индекс c которого брать указатель.
//! По умолчанию указывает на начало массива.
//! \~\code
//! PIVector<int> v{1, 3, 5};
//! int a[3];
//! memcpy(a, v.data(), a.size() * sizeof(int));
//! piCout << a[0] << a[1] << a[2]; // 1 3 5
//! \endcode
inline const T * data(size_t index = 0) const { return &(piv_data[index]); }
//! \~english Creates 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`).
PIVector<T> getRange(size_t index, size_t count) const {
if (index >= piv_size || count == 0) return PIVector<T>();
if (index + count > piv_size) count = piv_size - index;
return PIVector(piv_data + index, count);
}
//! \~english Clear array, remove all elements.
//! \~russian Очищает массив, удаляет все элементы.
//! \~\details
//! \~\note
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline PIVector<T> & clear() {
resize(0);
deleteT(piv_data, piv_size);
piv_size = 0;
return *this;
}
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 PIVector<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size)
piv_size = 0;
return *this;
}
inline PIVector<T> & fill(const T & f = T()) {
//! \~english Assigns element 'e' to all items in the array.
//! \~russian Заполняет весь массив копиями элемента 'e'.
//! \~\details
//! \code
//! PIVector<int> v{1, 3, 5};
//! v.fill(7);
//! piCout << v; // {7, 7, 7}
//! \endcode
//! \~\sa \a resize()
inline PIVector<T> & fill(const T & e = T()) {
deleteT(piv_data, piv_size);
PIINTROSPECTION_CONTAINER_USED(T, piv_size)
for (size_t i = 0; i < piv_size; ++i)
elementNew(piv_data + i, f);
for (size_t i = 0; i < piv_size; ++i) {
elementNew(piv_data + i, e);
}
return *this;
}
inline PIVector<T> & fill(std::function<T(size_t)> f) {
//! \~english Assigns result of function 'f(size_t i)' to all items in the array.
//! \~russian Заполняет весь массив результатом вызова функции 'f(size_t i)'.
//! \~\details
//! \code
//! PIVector<int> v{1, 3, 5};
//! v.fill([](size_t i){return i*2;});
//! piCout << v; // {0, 2, 4}
//! \endcode
//! \~\sa \a resize()
inline PIVector<T> & fill(std::function<T(size_t i)> f) {
deleteT(piv_data, piv_size);
PIINTROSPECTION_CONTAINER_USED(T, piv_size)
for (size_t i = 0; i < piv_size; ++i)
for (size_t i = 0; i < piv_size; ++i) {
elementNew(piv_data + i, f(i));
}
return *this;
}
inline PIVector<T> & assign(const T & f = T()) {return fill(f);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
//! \~english Same as \a fill().
//! \~russian Тоже самое что и \a fill().
//! \~\sa \a fill(), \a resize()
inline PIVector<T> & assign(const T & e = T()) { return fill(e); }
//! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline PIVector<T> & assign(size_t new_size, const T & f) {
resize(new_size);
return fill(f);
}
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 PIVector<T> & assign(size_t new_size, const T & f) {
_resizeRaw(new_size);
return fill(f);
}
inline PIVector<T> & resize(size_t new_size, const T & f = T()) {
//! \~english Sets size of the array, new elements are copied from `e`.
//! \~russian Устанавливает размер массива, новые элементы копируются из `e`.
//! \~\details
//! \~english If `new_size` is greater than the current \a size(),
//! elements are added to the end; the new elements are initialized from `e`.
//! If `new_size` is less than the current \a size(), elements are removed from the end.
//! \~russian Если `new_size` больше чем текущий размер массива \a size(),
//! новые элементы добавляются в конец массива и создаются из `e`.
//! Если `new_size` меньше чем текущий размер массива \a size(),
//! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear()
inline PIVector<T> & resize(size_t new_size, const T & e = T()) {
if (new_size < piv_size) {
T * de = &(piv_data[new_size]);
deleteT(de, piv_size - new_size);
deleteT(piv_data + new_size, piv_size - new_size);
piv_size = new_size;
}
if (new_size > piv_size) {
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);
} else if (new_size > piv_size) {
expand(new_size, e);
}
return *this;
}
inline PIVector<T> & resize(size_t new_size, std::function<T(size_t)> f) {
//! \~english Sets size of the array, new elements created by function `f(size_t i)`.
//! \~russian Устанавливает размер массива, новые элементы создаются функцией `f(size_t i)`.
//! \~\details
//! \~english If `new_size` is greater than the current \a size(),
//! elements are added to the end; the new elements created by function `f(size_t i)`.
//! If `new_size` is less than the current \a size(), elements are removed from the end.
//! \~russian Если `new_size` больше чем текущий размер массива \a size(),
//! новые элементы добавляются в конец массива и функцией `f(size_t i)`.
//! Если `new_size` меньше чем текущий размер массива \a size(),
//! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear()
inline PIVector<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size < piv_size) {
T * de = &(piv_data[new_size]);
deleteT(de, piv_size - new_size);
deleteT(piv_data + new_size, piv_size - new_size);
piv_size = new_size;
}
if (new_size > piv_size) {
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));
} else if (new_size > piv_size) {
expand(new_size, f);
}
return *this;
}
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 PIVector<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
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) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size-new_size));
PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size - new_size));
}
#endif
alloc(new_size);
return *this;
}
inline void _copyRaw(T * dst, const T * src, size_t size) {
newT(dst, src, size);
}
inline void _copyRaw(T * dst, const T * src, size_t size) { newT(dst, src, size); }
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
//! \~\details
//! \~english If you know in advance how large the array will be,
//! you should call this function to prevent reallocations and memory fragmentation.
//! If `new_size` is greater than the current \a capacity(),
//! new storage is allocated, otherwise the function does nothing.
//! This function does not change the \a size() of the array.
//! \~russian Если вы заранее знаете, насколько велик будет массив,
//! вы можете вызвать эту функцию, чтобы предотвратить перераспределение и фрагментацию памяти.
//! Если размер `new_size` больше чем выделенная память \a capacity(),
//! то произойдёт выделение новой памяти и перераспределение массива.
//! Эта функция не изменяет количество элементов в массиве \a size().
//! \~\sa \a size(), \a capacity(), \a resize()
inline PIVector<T> & reserve(size_t new_size) {
if (new_size <= piv_rsize) return *this;
size_t os = piv_size;
const size_t os = piv_size;
alloc(new_size);
piv_size = os;
return *this;
}
inline PIVector<T> & insert(size_t index, const T & v = T()) {
//! \~english Inserts value `e` at `index` position in the array.
//! \~russian Вставляет значение `e` в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than 0 and less than or equal to \a size().
//! \~russian Индекс должен быть больше 0 и меньше или равен \a size().
//! \code
//! PIVector<int> v{1, 3, 5};
//! v.insert(2, 7);
//! piCout << v; // {1, 3, 7, 5}
//! \endcode
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, const T & e = T()) {
alloc(piv_size + 1);
if (index < piv_size - 1) {
size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
const size_t os = piv_size - index - 1;
memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, v);
return *this;
}
inline PIVector<T> & insert(size_t index, T && v) {
alloc(piv_size + 1);
if (index < piv_size - 1) {
size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, std::move(v));
return *this;
}
inline PIVector<T> & insert(size_t index, const PIVector<T> & other) {
if (other.isEmpty()) return *this;
assert(&other != this);
ssize_t os = piv_size - index;
alloc(piv_size + other.piv_size);
if (os > 0)
memmove((void*)(&(piv_data[index + other.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
newT(piv_data + index, other.piv_data, other.piv_size);
elementNew(piv_data + index, e);
return *this;
}
//! \~english Inserts value `e` at `index` position in the array.
//! \~russian Вставляет значение `e` в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than 0 and less than or equal to \a size().
//! \~russian Индекс должен быть больше 0 и меньше или равен \a size().
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, T && e) {
alloc(piv_size + 1);
if (index < piv_size - 1) {
const size_t os = piv_size - index - 1;
memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
}
PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, std::move(e));
return *this;
}
//! \~english Inserts array `v` at `index` position in the array.
//! \~russian Вставляет массив `v` в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than or equal to 0 and less than or equal to \a size().
//! \~russian Индекс должен быть больше или равен 0 и меньше или равен \a size().
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, const PIVector<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
printf("error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const ssize_t os = piv_size - index;
alloc(piv_size + v.piv_size);
if (os > 0) {
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);
return *this;
}
//! \~english Inserts the given elements at `index` position in the array.
//! \~russian Вставляет элементы в позицию `index` в массиве.
//! \~\details
//! \~english The index must be greater than or equal to 0 and less than or equal to \a size().
//! Inserts the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Индекс должен быть больше или равен 0 и меньше или равен \a size().
//! Вставляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const ssize_t os = piv_size - index;
alloc(piv_size + init_list.size());
if (os > 0) {
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());
return *this;
}
//! \~english Removes `count` elements from the middle of the array, starting at `index` position.
//! \~russian Удаляет элементы из массива, начиная с позиции `index` в количестве `count`.
//! \~\details
//! \code
//! PIVector<int> v{1, 3, 7, 5};
//! v.remove(1, 2);
//! piCout << v; // {1, 5}
//! \endcode
//! \~\sa \a resize(), \a insert(), \a removeOne(), \a removeAll(), \a removeWhere()
inline PIVector<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this;
if (index + count >= piv_size) {
resize(index);
return *this;
if (index < piv_size) {
deleteT(piv_data + index, piv_size - index);
piv_size = index;
}
} else {
const size_t os = piv_size - index - count;
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;
}
size_t os = piv_size - index - count;
deleteT(&(piv_data[index]), count);
memmove((void*)(&(piv_data[index])), (const void*)(&(piv_data[index + count])), os * sizeof(T));
piv_size -= count;
return *this;
}
inline void swap(PIVector<T> & other) {
piSwap<T*>(piv_data, other.piv_data);
piSwap<size_t>(piv_size, other.piv_size);
piSwap<size_t>(piv_rsize, other.piv_rsize);
//! \~english Swaps array `v` other with this array.
//! \~russian Меняет местами массив `v` с этим массивом.
//! \~\details
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIVector<T> & v) {
piSwap<T *>(piv_data, v.piv_data);
piSwap<size_t>(piv_size, v.piv_size);
piSwap<size_t>(piv_rsize, v.piv_rsize);
}
typedef int (*CompareFunc)(const T * , const T * );
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);}
inline PIVector<T> & sort(CompareFunc compare = compare_func) {
piqsort(piv_data, piv_size, sizeof(T), (int(*)(const void * , const void * ))compare);
//! \~english Sorts the elements in non-descending order.
//! \~russian Сортировка элементов в порядке возрастания.
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using operator<.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется оператор `operator<`.
//! Для сортировки используется функция [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort).
//! Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort();
//! piCout << v; // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
//! \endcode
//! \~\sa \a sort(std::function<bool(const T &a, const T &b)> comp)
inline PIVector<T> & sort() {
std::sort(begin(), end());
return *this;
}
inline PIVector<T> & enlarge(llong piv_size) {
llong ns = size_s() + piv_size;
if (ns <= 0) clear();
else resize(size_t(ns));
//! \~english Sorts the elements in non-descending order.
//! \~russian Сортировка элементов в порядке возрастания.
//! \~\details
//! \~english The order of equal elements is not guaranteed to be preserved.
//! Elements are compared using the given binary comparison function `comp`.
//! which returns `true` if the first argument is less than (i.e. is ordered before) the second.
//! The signature of the comparison function should be equivalent to the following:
//! \code
//! bool comp(const T &a, const T &b);
//! \endcode
//! 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,
//! otherwise, it will lead to undefined program behavior and memory errors.
//! Sorting provided by [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort).
//! Complexity `O(N·log(N))`.
//! \~russian Сохранность порядка элементов, имеющих одинаковое значение, не гарантируется.
//! Для сравнения элементов используется функция сравнения `comp`.
//! Функция сравнения, возвращает `true` если первый аргумент меньше
//! второго. Сигнатура функции сравнения должна быть эквивалентна следующей: \code bool comp(const T &a, const T &b); \endcode Сигнатура
//! не обязана содержать const &, однако, функция не может изменять переданные объекты. Функция обязана возвращать `false` для
//! одинаковых элементов, иначе это приведёт к неопределённому поведению программы и ошибкам памяти. Для сортировки используется функция
//! [std::sort](https://ru.cppreference.com/w/cpp/algorithm/sort). Сложность сортировки `O(N·log(N))`.
//! \~\code
//! PIVector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
//! v.sort([](const int & a, const int & b){return a > b;});
//! piCout << v; // {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
//! \endcode
//! \~\sa \a sort()
inline PIVector<T> & sort(std::function<bool(const T & a, const T & b)> comp) {
std::sort(begin(), end(), comp);
return *this;
}
inline PIVector<T> & removeOne(const T & v) {
for (size_t i = 0; i < piv_size; ++i)
if (piv_data[i] == v) {
//! \~english Reverses this array.
//! \~russian Обращает порядок следования элементов этого массива.
//! \~\details
//! \~english This method reverses an array [in place](https://en.wikipedia.org/wiki/In-place_algorithm).
//! The first array element becomes the last, and the last array element becomes the first.
//! The reverse method transposes the elements of the calling array object in place,
//! mutating the array, and returning a reference to the array.
//! \~russian Метод reverse() на месте переставляет элементы массива,
//! на котором он был вызван, изменяет массив и возвращает ссылку на него.
//! Первый элемент массива становится последним, а последний — первым.
//! \~\code
//! PIVector<int> v{1, 3, 7, 5};
//! v.reverse();
//! piCout << v; // {5, 7, 3, 1}
//! \endcode
//! \~\sa \a reversed()
inline PIVector<T> & reverse() {
const size_t s2 = piv_size / 2;
for (size_t i = 0; i < s2; ++i) {
piSwap<T>(piv_data[i], piv_data[piv_size - i - 1]);
}
return *this;
}
//! \~english Returns reversed array.
//! \~russian Возвращает перевернутый массив.
//! \~\details
//! \~english Returns a copy of the array with elements in reverse order.
//! The first array element becomes the last, and the last array element becomes the first.
//! \~russian Возвращает копию массива с элементами в обратном порядке.
//! Первый элемент массива становится последним, а последний — первым.
//! \~\sa \a reverse()
inline PIVector<T> reversed() const {
PIVector<T> ret(*this);
return ret.reverse();
}
//! \~english Increases or decreases the size of the array by `add_size` elements.
//! \~russian Увеличивает или уменьшает размер массива на `add_size` элементов.
//! \~\details
//! \~english If `add_size > 0` then elements are added to the end of the array.
//! If `add_size < 0` then elements are removed from the end of the array.
//! If `add_size < 0` and there are fewer elements in the array than specified, then the array becomes empty.
//! \~russian Если `add_size > 0`, то в конец массива добавляются элементы.
//! Если `add_size < 0`, то с конца массива удаляются элементы.
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize()
inline PIVector<T> & enlarge(ssize_t add_size, const T & e = T()) {
const ssize_t ns = size_s() + add_size;
if (ns <= 0)
clear();
else
resize(size_t(ns), e);
return *this;
}
//! \~english Remove no more than one element equal `e`.
//! \~russian Удаляет первый элемент, который равен элементу `e`.
//! \~\details
//! \~\code
//! PIVector<int> v{3, 2, 5, 2, 7};
//! v.removeOne(2);
//! piCout << v; // {3, 5, 2, 7}
//! \endcode
//! \~\sa \a remove(), \a removeAll(), \a removeWhere()
inline PIVector<T> & removeOne(const T & e) {
for (size_t i = 0; i < piv_size; ++i) {
if (piv_data[i] == e) {
remove(i);
return *this;
}
}
return *this;
}
inline PIVector<T> & removeAll(const T & v) {
for (ssize_t i = 0; i < ssize_t(piv_size); ++i)
if (piv_data[i] == v) {
remove(i);
--i;
//! \~english Remove all elements equal `e`.
//! \~russian Удаляет все элементы, равные элементу `e`.
//! \~\details
//! \~\code
//! PIVector<int> v{3, 2, 5, 2, 7};
//! v.removeAll(2);
//! piCout << v; // {3, 5, 7}
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIVector<T> & removeAll(const T & e) {
ssize_t j = indexOf(e);
if (j != -1) {
for (size_t i = j + 1; i < piv_size; ++i) {
if (piv_data[i] != e) {
piv_data[j++] = std::move(piv_data[i]);
}
}
remove(j, piv_size - j);
}
return *this;
}
inline PIVector<T> & push_back(const T & v) {
//! \~english Remove all elements in the array
//! passes the test implemented by the provided function `test`.
//! \~russian Удаляет все элементы, удовлетворяющие условию,
//! заданному в передаваемой функции `test`.
//! \~\details
//! \~\code
//! PIVector<int> v{3, 2, 5, 2, 7};
//! v.removeWhere([](const int & i){return i > 2;});
//! piCout << v; // {2, 2}
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIVector<T> & removeWhere(std::function<bool(const T & e)> test) {
ssize_t j = indexWhere(test);
if (j != -1) {
for (size_t i = j + 1; i < piv_size; ++i) {
if (!test(piv_data[i])) {
piv_data[j++] = std::move(piv_data[i]);
}
}
remove(j, piv_size - j);
}
return *this;
}
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~english If size() is less than capacity(), which is most often
//! then the addition will be very fast.
//! In any case, the addition is fast and does not depend on the size of the array.
//! If the new size() is greater than capacity()
//! then all iterators and references
//! (including the past-the-end iterator) are invalidated.
//! Otherwise only the past-the-end iterator is invalidated.
//! \~russian Если size() меньше capacity(), что часто бывает,
//! то добавление будет очень быстрым.
//! В любом случае добавление быстрое и не зависит от размера массива.
//! Если новый size() больше, чем capacity(),
//! то все итераторы и указатели становятся нерабочими.
//! В противном случае все, кроме итераторов, указывающих на конец массива,
//! остаются в рабочем состоянии.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.push_back(4);
//! v.push_back(5);
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a push_front(), \a append(), \a prepend(), \a insert()
inline PIVector<T> & push_back(const T & e) {
alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, v);
elementNew(piv_data + piv_size - 1, e);
return *this;
}
inline PIVector<T> & push_back(T && v) {
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a push_back()
inline PIVector<T> & push_back(T && e) {
alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, std::move(v));
elementNew(piv_data + piv_size - 1, std::move(e));
return *this;
}
inline PIVector<T> & append(const T & v) {return push_back(v);}
inline PIVector<T> & append(T && v) {return push_back(std::move(v));}
inline PIVector<T> & append(const PIVector<T> & other) {
assert(&other != this);
size_t ps = piv_size;
alloc(piv_size + other.piv_size);
newT(piv_data + ps, other.piv_data, other.piv_size);
//! \~english Appends the given elements to the end of the array.
//! \~russian Добавляет элементы в конец массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back()
inline PIVector<T> & push_back(std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const size_t ps = piv_size;
alloc(piv_size + init_list.size());
newT(piv_data + ps, init_list.begin(), init_list.size());
return *this;
}
inline PIVector<T> & operator <<(const T & v) {return push_back(v);}
inline PIVector<T> & operator <<(T && v) {return push_back(std::move(v));}
inline PIVector<T> & operator <<(const PIVector<T> & other) {return append(other);}
inline PIVector<T> & push_front(const T & v) {insert(0, v); return *this;}
inline PIVector<T> & push_front(T && v) {insert(0, std::move(v)); return *this;}
inline PIVector<T> & prepend(const T & v) {return push_front(v);}
inline PIVector<T> & prepend(T && v) {return push_front(std::move(v));}
//! \~english Appends the given array `v` to the end of the array.
//! \~russian Добавляет массив `v` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a push_back()
inline PIVector<T> & push_back(const PIVector<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const size_t ps = piv_size;
alloc(piv_size + v.piv_size);
newT(piv_data + ps, v.piv_data, v.piv_size);
return *this;
}
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~\details
//! \~english If size() is less than capacity(), which is most often
//! then the addition will be very fast.
//! In any case, the addition is fast and does not depend on the size of the array.
//! If the new size() is greater than capacity()
//! then all iterators and references
//! (including the past-the-end iterator) are invalidated.
//! Otherwise only the past-the-end iterator is invalidated.
//! \~russian Если size() меньше capacity(), что часто бывает,
//! то добавление будет очень быстрым.
//! В любом случае добавление быстрое и не зависит от размера массива.
//! Если новый size() больше, чем capacity(),
//! то все итераторы и указатели становятся нерабочими.
//! В противном случае все, кроме итераторов, указывающих на конец массива,
//! остаются в рабочем состоянии.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.append(4);
//! v.append(5);
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a prepend(), \a push_front(), \a push_back(), \a insert()
inline PIVector<T> & append(const T & e) { return push_back(e); }
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a append()
inline PIVector<T> & append(T && e) { return push_back(std::move(e)); }
//! \~english Appends the given elements to the end of the array.
//! \~russian Добавляет элементы в конец массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIVector<T> & append(std::initializer_list<T> init_list) { return push_back(init_list); }
//! \~english Appends the given array `v` to the end of the array.
//! \~russian Добавляет массив `v` в конец массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.append(PIVector<int>{4, 5});
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & append(const PIVector<T> & v) { return push_back(v); }
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v << 4 << 5;
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & operator<<(const T & e) { return push_back(e); }
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v << 4 << 5;
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & operator<<(T && e) { return push_back(std::move(e)); }
//! \~english Appends the given array `v` to the end of the array.
//! \~russian Добавляет массив `v` в конец массива.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v << PIVector<int>{4, 5};
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & operator<<(const PIVector<T> & v) { return push_back(v); }
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english Adding an element to the beginning takes longer than to the end.
//! This time is directly proportional to the size of the array.
//! All iterators and references are invalidated.
//! \~russian Добавление элемента в начало выполняется дольше, чем в конец.
//! Это время прямопропорционально размеру массива.
//! При добавлении элемента все итераторы и указатели становятся нерабочими.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.push_front(4);
//! v.push_front(5);
//! piCout << v; // {5, 4, 1, 2, 3}
//! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIVector<T> & push_front(const T & e) { return insert(0, e); }
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a push_front()
inline PIVector<T> & push_front(T && e) { return insert(0, std::move(e)); }
//! \~english Appends the given array `v` to the begin of the array.
//! \~russian Добавляет массив `v` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.push_front(PIVector<int>{4, 5});
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a push_front()
inline PIVector<T> & push_front(const PIVector<T> & v) { return insert(0, v); }
//! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIVector<T> & push_front(std::initializer_list<T> init_list) { return insert(0, init_list); }
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english Adding an element to the beginning takes longer than to the end.
//! This time is directly proportional to the size of the array.
//! All iterators and references are invalidated.
//! \~russian Добавление элемента в начало выполняется дольше, чем в конец.
//! Это время прямопропорционально размеру массива.
//! При добавлении элемента все итераторы и указатели становятся нерабочими.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.prepend(4);
//! v.prepend(5);
//! piCout << v; // {5, 4, 1, 2, 3}
//! \endcode
//! \~\sa \a append(), \a push_back(), \a push_front(), \a insert()
inline PIVector<T> & prepend(const T & e) { return push_front(e); }
//! \~english Appends the given element `e` to the begin of the array.
//! \~russian Добавляет элемент `e` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a prepend()
inline PIVector<T> & prepend(T && e) { return push_front(std::move(e)); }
//! \~english Appends the given array `v` to the begin of the array.
//! \~russian Добавляет массив `v` в начало массива.
//! \~\details
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.prepend(PIVector<int>{4, 5});
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a prepend()
inline PIVector<T> & prepend(const PIVector<T> & v) { return push_front(v); }
//! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива.
//! \~\details
//! \~english Overloaded function.
//! Appends the given elements from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Перегруженая функция.
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIVector<T> & prepend(std::initializer_list<T> init_list) { return prepend(init_list); }
//! \~english Remove one element from the end of the array.
//! \~russian Удаляет один элемент с конца массива.
//! \~\details
//! \~english Deleting an element from the end is very fast
//! and does not depend on the size of the array.
//! \~russian Удаление элемента с конца выполняется очень быстро
//! и не зависит от размера массива.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.pop_back();
//! piCout << v; // {1, 2}
//! \endcode
//! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIVector<T> & pop_back() {
if (piv_size == 0)
return *this;
resize(piv_size - 1);
if (piv_size == 0) return *this;
deleteT(piv_data + piv_size - 1, 1);
piv_size = piv_size - 1;
return *this;
}
//! \~english Remove one element from the begining of the array.
//! \~russian Удаляет один элемент с начала массива.
//! \~\details
//! \~english Removing an element from the beginning takes longer than from the end.
//! This time is directly proportional to the size of the array.
//! All iterators and references are invalidated.
//! \~russian Удаление элемента с начала выполняется дольше, чем с конца.
//! Это время прямопропорционально размеру массива.
//! При удалении элемента все итераторы и указатели становятся нерабочими.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! v.pop_front();
//! piCout << v; // {2, 3}
//! \endcode
//! \~\sa \a pop_back(), \a take_back(), \a take_front()
inline PIVector<T> & pop_front() {
if (piv_size == 0)
return *this;
if (piv_size == 0) return *this;
remove(0);
return *this;
}
inline T take_back() {T t(back()); pop_back(); return t;}
inline T take_front() {T t(front()); pop_front(); return t;}
//! \~english Remove one element from the end of the array and return it.
//! \~russian Удаляет один элемент с начала массива и возвращает его.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! piCout << v.take_back(); // 3
//! piCout << v; // {1, 2}
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() {
const T e(back());
pop_back();
return e;
}
template <typename ST>
PIVector<ST> toType() const {
PIVector<ST> ret(piv_size);
for (uint i = 0; i < piv_size; ++i)
ret[i] = ST(piv_data[i]);
//! \~english Remove one element from the begining of the array and return it.
//! \~russian Удаляет один элемент с конца массива и возвращает его.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! piCout << v.take_front(); // 1
//! piCout << v; // {2, 3}
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() {
const T e(front());
pop_front();
return e;
}
//! \~english Returns an array converted to another type.
//! \~russian Возвращает конвертированный в другой тип массив.
//! \~\details
//! \~\code
//! PIVector<double> v{1.1, 2.5, 3.8};
//! PIVector<int> v2 = v.toType<int>();
//! piCout << v2; // {1, 2, 3}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIVector<ST> toType() const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) {
ret << ST(piv_data[i]);
}
return ret;
}
const PIVector<T> & forEach(std::function<void(const T &)> f) const {
for (uint i = 0; i < piv_size; ++i)
//! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `bool test(const T & e)`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`.
//! \~\details
//! \~\code
//! PIVector<int> v{3, 2, 5, 2, 7};
//! PIVector<int> v2 = v.filter([](const int & i){return i > 2;});
//! piCout << v2; // {3, 5, 7}
//! \endcode
//! \~\sa \a map(), \a any(), \a every()
inline PIVector<T> filter(std::function<bool(const T & e)> test) const {
PIVector<T> ret;
for (size_t i = 0; i < piv_size; ++i) {
if (test(piv_data[i])) ret << piv_data[i];
}
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.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details
//! \~russian Не позволяет изменять элементы массива.
//! Для редактирования элементов используйте функцию вида `void f(T & e)`.
//! \~english Does not allow changing array elements.
//! To edit elements, use the function like `void f(T & e)`
//! \~\code
//! PIVector<int> v{1, 2, 3, 4, 5};
//! int s = 0;
//! v.forEach([&s](const int & e){s += e;});
//! piCout << s; // 15
//! \endcode
//! \~\sa \a filter(), \a map(), \a reduce(), \a any(), \a every()
inline void forEach(std::function<void(const T & e)> f) const {
for (size_t i = 0; i < piv_size; ++i) {
f(piv_data[i]);
}
}
//! \~english Execute function `void f(T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(T & e)` для каждого элемента массива.
//! \~\details
//! \~english Overloaded function.
//! Allows you to change the elements of the array.
//! \~russian Перегруженая функция.
//! Позволяет изменять элементы массива.
//! \~\code
//! PIVector<int> v{1, 2, 3, 4, 5};
//! v.forEach([](int & e){e++;});
//! piCout << v; // {2, 3, 4, 5, 6}
//! \endcode
//! \~\sa \a filter(), \a map(), \a reduce(), \a any(), \a every()
inline PIVector<T> & forEach(std::function<void(T & e)> f) {
for (size_t i = 0; i < piv_size; ++i) {
f(piv_data[i]);
}
return *this;
}
PIVector<T> copyForEach(std::function<T(const T &)> f) const {
PIVector<T> ret; ret.reserve(piv_size);
for (uint i = 0; i < piv_size; ++i)
ret << f(piv_data[i]);
return ret;
//! \~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]);
}
}
PIVector<T> & forEachInplace(std::function<T(const T &)> f) {
for (uint i = 0; i < piv_size; ++i)
piv_data[i] = f(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;
}
template <typename ST>
PIVector<ST> toType(std::function<ST(const T &)> f) const {
PIVector<ST> ret; ret.reserve(piv_size);
for (uint i = 0; i < piv_size; ++i)
//! \~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
//! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции
//! `ST f(const T & e)` для каждого элемента массива.
//! \~\details
//! \~english Calls a provided function`ST f(const T & e)`
//! once for each element in an array, in order,
//! and constructs a new array from the results.
//! \~russian Метод `map` вызывает переданную функцию `ST f(const T & e)`
//! один раз для каждого элемента в порядке их появления
//! и конструирует новый массив из результатов её вызова.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.map<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"1", "2", "3"}
//! \endcode
//! \~\sa \a forEach(), \a reduce()
template<typename ST>
inline PIVector<ST> map(std::function<ST(const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) {
ret << f(piv_data[i]);
}
return ret;
}
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, int order = byRow) const {
//! \~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)`
//! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
//! к каждому элементу массива (слева-направо), возвращает одно значение.
//! \~\details
//! \~english The reduce() method performs the `f` function
//! once for each element in the array.
//! If the `initial` argument is passed when calling reduce(),
//! then when the function `f` is called for the first time,
//! the value of `acc` will be assigned to `initial`.
//! If the array is empty, the value `initial` will be returned.
//! \param f is a function like `ST f(const T & e, const ST & acc)`,
//! executed for each element of the array. It takes two arguments:
//! * **e** - current element of the array
//! * **acc** - accumulator accumulating the value
//! which this function returns after visiting the next element
//!
//! \param initial _optional_ Object used as the second argument
//! when the `f` function is first called.
//! \~russian Метод reduce() выполняет функцию `f`
//! один раз для каждого элемента, присутствующего в массиве.
//! Если при вызове reduce() передан аргумент `initial`,
//! то при первом вызове функции `f` значение `acc`
//! будет равным значению `initial`.
//! Если массив пустой то будет возвращено значение `initial`.
//! \param f Функция, вида `ST f(const T & e, const ST & acc)`,
//! выполняющаяся для каждого элемента массива.
//! Она принимает два аргумента:
//! * **e** - текущий элемент массива
//! * **acc** - аккумулятор, аккумулирующий значение
//! которое возвращает эта функция после посещения очередного элемента
//!
//! \param initial _опциональный_ Объект,
//! используемый в качестве второго аргумента при первом вызове функции `f`.
//!
//! \~\code
//! PIVector<int> v{1, 2, 3, 4, 5};
//! int s = v.reduce<int>([](const int & e, const int & acc){return e + acc;});
//! piCout << s; // 15
//! \endcode
//! \~\sa \a forEach(), \a map()
template<typename ST>
inline ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < piv_size; ++i) {
ret = f(piv_data[i], ret);
}
return ret;
}
//! \~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.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details
//! \~russian
//! \param rows размер внешнего массива
//! \param cols размер внутренних массивов
//! \param order порядок обхода исходного массива, задаётся с помощью \a ReshapeOrder
//! \~english
//! \param rows size external array
//! \param cols size internal arrays
//! \param order the order of traversing the source array is set using \a ReshapeOrder
//! \~\code
//! PIVector<int> v{1, 2, 3, 4};
//! PIVector<PIVector<int>> m1 = v.reshape(2,2);
//! piCout << m1; // {{1, 2}, {3, 4}}
//! PIVector<PIVector<int>> m2 = v.reshape(2,2, ReshapeByColumn);
//! piCout << m2; // {{1, 3}, {2, 4}}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a flatten()
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
#ifndef NDEBUG
if (rows * cols != piv_size) {
printf("error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
}
#endif
assert(rows * cols == piv_size);
PIVector<PIVector<T>> ret;
if (isEmpty()) return ret;
assert(rows*cols == piv_size);
ret.resize(rows);
if (order == byRow) {
for (size_t r = 0; r < rows; r++)
ret[r] = PIVector<T>(&(piv_data[r*cols]), cols);
ret.expand(rows);
if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) {
ret[r] = PIVector<T>(&(piv_data[r * cols]), cols);
}
}
if (order == byColumn) {
if (order == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols);
for (size_t c = 0; c < cols; c++)
ret[r][c] = piv_data[c*rows + r];
for (size_t c = 0; c < cols; c++) {
ret[r][c] = piv_data[c * rows + r];
}
}
}
return ret;
}
template<typename C, typename std::enable_if<
std::is_same<T, PIVector<C>>::value
, int>::type = 0>
inline PIVector<C> reshape(int order = byRow) const {
//! \~english Changes the dimension of the array, creates a one-dimensional array from a two-dimensional array.
//! \~russian Изменяет размерность массива, из двухмерный массива создает одномерный.
//! \~\details
//! \~russian Делает массив плоским.
//! Порядок обхода исходного массива задаётся с помощью \a ReshapeOrder.
//! \~english Makes the array flat.
//! Еhe order of traversing the source array is set using \a ReshapeOrder.
//! \~\code
//! PIVector<int> v{1, 2, 3, 4, 5, 6};
//! PIVector<PIVector<int>> xv = v.reshape(3,2);
//! piCout << xv; // {{1, 2}, {3, 4}, {5, 6}}
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if<std::is_same<T, PIVector<C>>::value, int>::type = 0>
inline PIVector<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIVector<C> ret;
if (isEmpty()) return ret;
size_t rows = size();
size_t cols = at(0).size();
const size_t rows = size();
const size_t cols = at(0).size();
ret.reserve(rows * cols);
if (order == byRow) {
for (size_t r = 0; r < rows; r++)
if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) {
ret.append(at(r));
}
}
if (order == byColumn) {
for (size_t c = 0; c < cols; c++)
for (size_t r = 0; r < rows; r++)
if (order == ReshapeByColumn) {
for (size_t c = 0; c < cols; c++) {
for (size_t r = 0; r < rows; r++) {
ret << at(r)[c];
}
}
}
ret.resize(rows * cols);
return ret;
}
//! \~english Changes the dimension of the two-dimensional array.
//! \~russian Изменяет размерность двухмерного массива.
//! \~\details
//! \~russian
//! \param rows размер внешнего массива
//! \param cols размер внутренних массивов
//! \param order порядок обхода исходного массива, задаётся с помощью \a ReshapeOrder
//! \~english
//! \param rows size external array
//! \param cols size internal arrays
//! \param order the order of traversing the source array is set using \a ReshapeOrder
//! \~\code
//! PIVector<int> v{1, 2, 3, 4, 5, 6};
//! PIVector<PIVector<int>> xv = v.reshape(3,2);
//! piCout << xv; // {{1, 2}, {3, 4}, {5, 6}}
//! piCout << xv.reshape<int>(2,3); // {{1, 2, 3}, {4, 5, 6}}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if<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 {
PIVector<C> fl = flatten<C>();
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:
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
inline void _reset() {
piv_size = 0;
piv_rsize = 0;
piv_data = nullptr;
}
inline size_t asize(size_t s) {
if (s == 0) return 0;
if (piv_rsize + piv_rsize >= s && piv_rsize < s)
return piv_rsize + piv_rsize;
ssize_t t = 0, s_ = s - 1;
while (s_ >> t) ++t;
if (piv_rsize * 2 >= s && piv_rsize < s) {
return piv_rsize * 2;
}
ssize_t t = _PIContainerConstants<T>::minCountPoT();
s -= 1;
while (s >> t)
++t;
return (1 << t);
}
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) {
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]);
}
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) {
PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy((void*)(dst), (const void*)(src), s * sizeof(T));
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i)
elementDelete(d[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) {
PIINTROSPECTION_CONTAINER_USED(T, s)
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, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if (d != nullptr) {
for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]);
}
}
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, const 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, const 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 (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) {
if (new_size <= piv_rsize) {
piv_size = new_size;
return;
}
piv_size = new_size;
size_t as = asize(new_size);
piv_size = new_size;
const size_t as = asize(new_size);
if (as == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T)));
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - piv_rsize))
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), as * sizeof(T)));
#ifndef NDEBUG
if (!p_d) {
printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
piv_data = p_d;
piv_data = p_d;
piv_rsize = as;
}
T * piv_data;
size_t piv_size, piv_rsize;
T * piv_data = nullptr;
size_t piv_size = 0;
size_t piv_rsize = 0;
};
#ifdef PIP_STD_IOSTREAM
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename T>
inline std::ostream & operator <<(std::ostream & s, const PIVector<T> & v) {s << "{"; for (size_t i = 0; i < v.size(); ++i) {s << v[i]; if (i < v.size() - 1) s << ", ";} s << "}"; return s;}
#endif
template<typename T>
inline PICout operator <<(PICout s, const PIVector<T> & v) {
s.space();
s.setControl(0, true);
inline std::ostream & operator<<(std::ostream & s, const PIVector<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1)
s << ", ";
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControl();
return s;
}
#endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename T>
inline PICout operator<<(PICout s, const PIVector<T> & v) {
s.space();
s.saveAndSetControls(0);
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) {
s << ", ";
}
}
s << "}";
s.restoreControls();
return s;
}
template<typename T> inline void piSwap(PIVector<T> & f, PIVector<T> & s) {f.swap(s);}
template<typename T>
inline void piSwap(PIVector<T> & f, PIVector<T> & s) {
f.swap(s);
}
#endif // PIVECTOR_H

View File

@@ -1,25 +1,25 @@
/*! @file pivector2d.h
* @brief 2D wrapper around PIVector
/*! \file pivector2d.h
* \brief 2D wrapper around PIVector
*
* This file declares PIVector
*/
*/
/*
PIP - Platform Independent Primitives
2D wrapper around PIVector
Andrey Bychkov work.a.b@yandex.ru
PIP - Platform Independent Primitives
2D wrapper around PIVector
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 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.
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/>.
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 PIVECTOR2D_H
@@ -27,7 +27,7 @@
#include "pivector.h"
/*! @brief 2D array,
/*! \brief 2D array,
* \details This class used to store 2D array of any type elements as plain vector.
* You can read/write any element via operators [][], first dimension - row, second - column.
* The first dimension is Row, and you can operate with Row as PIVector<T>: modify any element, assign to another Row and etc.
@@ -35,161 +35,195 @@
* PIVector2D has constructors from PIVector<T> and PIVector<PIVector<T> >
*/
template <typename T>
template<typename T>
class PIVector2D {
public:
inline PIVector2D() {rows_ = cols_ = 0;}
inline PIVector2D() { rows_ = cols_ = 0; }
inline PIVector2D(size_t rows, size_t cols, const T & f = T()) {
rows_ = rows;
cols_ = cols;
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, PIVector<T> && v) : rows_(rows), cols_(cols), mat(std::move(v)) {
mat.resize(rows*cols);
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, PIVector<T> && v): rows_(rows), cols_(cols), mat(std::move(v)) { mat.resize(rows * cols); }
inline PIVector2D(const PIVector<PIVector<T>> & v) {
rows_ = v.size();
if (rows_) {
cols_ = v[0].size();
mat.reserve(rows_*cols_);
mat.reserve(rows_ * cols_);
for (size_t i = 0; i < rows_; i++) {
mat.append(v[i]);
}
mat.resize(rows_*cols_);
mat.resize(rows_ * cols_);
}
if (mat.isEmpty()) rows_ = cols_ = 0;
}
inline size_t rows() const {return rows_;}
inline size_t cols() const {return cols_;}
inline size_t size() const {return mat.size();}
inline ssize_t size_s() const {return mat.size_s();}
inline size_t length() const {return mat.length();}
inline size_t capacity() const {return mat.capacity();}
inline bool isEmpty() const {return mat.isEmpty();}
inline size_t rows() const { return rows_; }
inline size_t cols() const { return cols_; }
inline size_t size() const { return mat.size(); }
inline ssize_t size_s() const { return mat.size_s(); }
inline size_t length() const { return mat.length(); }
inline size_t capacity() const { return mat.capacity(); }
inline bool isEmpty() const { return mat.isEmpty(); }
inline bool isNotEmpty() const { return mat.isNotEmpty(); }
class Row {
friend class PIVector2D<T>;
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_;
size_t st_, sz_;
public:
inline size_t size() const {return sz_;}
inline T & operator [](size_t index) {return (*p_)[st_ + index];}
inline const T & operator [](size_t index) const {return (*p_)[st_ + index];}
inline T * data(size_t index = 0) {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 size_t size() const { return sz_; }
inline T & operator[](size_t index) { return (*p_)[st_ + index]; }
inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; }
inline T * data(size_t index = 0) { 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) {
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);
return *this;
}
inline Row & operator =(const PIVector<T> & other) {
size_t sz = piMin<size_t>(sz, other.size());
inline Row & operator=(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(sz, other.size());
p_->_copyRaw(p_->data(st_), other.data(), sz);
return *this;
}
inline PIVector<T> toVector() const {return PIVector<T>(p_->data(st_), sz_);}
inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); }
};
class Col {
friend class PIVector2D<T>;
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_;
size_t step_, row_, sz_;
public:
inline size_t size() const {return sz_;}
inline T & operator [](size_t index) {return (*p_)[index * step_ + row_];}
inline const T & operator [](size_t index) const {return (*p_)[index * step_ + row_];}
inline T * data(size_t index = 0) {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 size_t size() const { return sz_; }
inline T & operator[](size_t index) { return (*p_)[index * step_ + row_]; }
inline const T & operator[](size_t index) const { return (*p_)[index * step_ + row_]; }
inline T * data(size_t index = 0) { 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) {
if (p_ == other.p_ && row_ == other.row_) return *this;
size_t sz = piMin<size_t>(sz_, other.sz_);
for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i];
const size_t sz = piMin<size_t>(sz_, other.sz_);
for (int i = 0; i < sz; ++i)
(*p_)[i * step_ + row_] = other[i];
return *this;
}
inline Row & operator =(const PIVector<T> & other) {
size_t sz = piMin<size_t>(sz_, other.size());
for (int i=0; i<sz; ++i) (*p_)[i * step_ + row_] = other[i];
inline Row & operator=(const PIVector<T> & other) {
const size_t sz = piMin<size_t>(sz_, other.size());
for (int i = 0; i < sz; ++i)
(*p_)[i * step_ + row_] = other[i];
return *this;
}
inline PIVector<T> toVector() const {
PIVector<T> ret;
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;
}
};
class RowConst {
friend class PIVector2D<T>;
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_;
size_t st_, sz_;
public:
inline size_t size() const {return sz_;}
inline const T & operator [](size_t index) const {return (*p_)[st_ + index];}
inline const T * data(size_t index = 0) const {return p_->data(st_ + index);}
inline PIVector<T> toVector() const {return PIVector<T>(p_->data(st_), sz_);}
inline size_t size() const { return sz_; }
inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; }
inline const T * data(size_t index = 0) const { return p_->data(st_ + index); }
inline PIVector<T> toVector() const { return PIVector<T>(p_->data(st_), sz_); }
};
class ColConst {
friend class PIVector2D<T>;
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_;
size_t step_, row_, sz_;
public:
inline size_t size() const {return p_->rows_;}
inline const T & operator [](size_t index) const {return (*p_)[index * step_ + row_];}
inline const T * data(size_t index = 0) const {return p_->data(index * step_ + row_);}
inline size_t size() const { return p_->rows_; }
inline const T & operator[](size_t index) const { return (*p_)[index * step_ + row_]; }
inline const T * data(size_t index = 0) const { return p_->data(index * step_ + row_); }
inline PIVector<T> toVector() const {
PIVector<T> ret;
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;
}
};
inline T & element(size_t row, size_t col) {return mat[row * cols_ + col];}
inline const T & element(size_t row, size_t col) const {return mat[row * cols_ + col];}
inline const T & at(size_t row, size_t col) const {return mat[row * cols_ + col];}
inline Row operator[](size_t index) {return Row(this, index);}
inline RowConst operator[](size_t index) const {return RowConst(this, index);}
inline T * data(size_t index = 0) {return mat.data(index);}
inline const T * data(size_t index = 0) const {return mat.data(index);}
inline T & element(size_t row, size_t col) { return mat[row * cols_ + col]; }
inline const T & element(size_t row, size_t col) const { return mat[row * cols_ + col]; }
inline const T & at(size_t row, size_t col) const { return mat[row * cols_ + col]; }
inline Row operator[](size_t index) { return Row(this, index); }
inline RowConst operator[](size_t index) const { return RowConst(this, index); }
inline T * data(size_t index = 0) { return mat.data(index); }
inline const T * data(size_t index = 0) const { return mat.data(index); }
inline Row row(size_t index) {return Row(this, index);}
inline RowConst row(size_t index) const {return RowConst(this, index);}
inline Col col(size_t index) {return Col(this, index);}
inline ColConst col(size_t index) const {return ColConst(this, index);}
inline Row row(size_t index) { return Row(this, index); }
inline RowConst row(size_t index) const { return RowConst(this, index); }
inline Col col(size_t index) { return Col(this, index); }
inline ColConst col(size_t index) const { return ColConst(this, index); }
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);
return *this;
}
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);
return *this;
}
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);
return *this;
}
inline PIVector2D<T> & addRow(const Row & other) {
if (cols_ == 0) cols_ = other.sz_;
size_t sz = piMin<size_t>(cols_, other.sz_);
size_t ps = mat.size();
const size_t sz = piMin<size_t>(cols_, other.sz_);
const size_t ps = mat.size();
mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++;
@@ -197,8 +231,8 @@ public:
}
inline PIVector2D<T> & addRow(const RowConst & other) {
if (cols_ == 0) cols_ = other.sz_;
size_t sz = piMin<size_t>(cols_, other.sz_);
size_t ps = mat.size();
const size_t sz = piMin<size_t>(cols_, other.sz_);
const size_t ps = mat.size();
mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++;
@@ -206,8 +240,8 @@ public:
}
inline PIVector2D<T> & addRow(const PIVector<T> & other) {
if (cols_ == 0) cols_ = other.size();
size_t sz = piMin<size_t>(cols_, other.size());
size_t ps = mat.size();
const size_t sz = piMin<size_t>(cols_, other.size());
const size_t ps = mat.size();
mat.resize(mat.size() + cols_);
mat._copyRaw(mat.data(ps), other.data(), sz);
rows_++;
@@ -215,20 +249,20 @@ public:
}
inline PIVector2D<T> & resize(size_t rows, size_t cols, const T & f = T()) {
mat.resize(rows*cols_, f);
rows_ = rows;
int cs = (cols - cols_);
mat.resize(rows * cols_, f);
rows_ = rows;
const int cs = (cols - cols_);
if (cs < 0) {
for (size_t r=0; r<rows; ++r) {
mat.remove(r*cols + cols, -cs);
for (size_t r = 0; r < rows; ++r) {
mat.remove(r * cols + cols, -cs);
}
}
mat.resize(rows*cols, f);
mat.resize(rows * cols, f);
if (!mat.isEmpty()) {
if (cs > 0) {
for (size_t r=0; r<rows_; ++r) {
for (int i=0; i<cs; ++i)
mat.insert(r*cols + cols_, mat.take_back());
for (size_t r = 0; r < rows_; ++r) {
for (int i = 0; i < cs; ++i)
mat.insert(r * cols + cols_, mat.take_back());
}
}
}
@@ -236,23 +270,25 @@ public:
return *this;
}
inline bool operator ==(const PIVector2D<T> & t) const {
if (cols_ != t.cols_ || rows_ != t.rows_)
return false;
inline bool operator==(const PIVector2D<T> & t) const {
if (cols_ != t.cols_ || rows_ != t.rows_) return false;
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 {
PIVector<PIVector<T> > ret;
inline PIVector<PIVector<T>> toVectors() const {
PIVector<PIVector<T>> ret;
ret.reserve(rows_);
for(size_t i = 0; i < rows_; ++i)
ret << PIVector<T>(mat.data(i*cols_), cols_);
for (size_t i = 0; i < rows_; ++i)
ret << PIVector<T>(mat.data(i * cols_), cols_);
return ret;
}
PIVector<T> toPlainVector() const {return mat;}
PIVector<T> & plainVector() {return mat;}
const PIVector<T> & plainVector() const {return mat;}
inline PIVector<T> toPlainVector() const { return mat; }
inline PIVector<T> & plainVector() { return mat; }
inline const PIVector<T> & plainVector() const { return mat; }
inline void swap(PIVector2D<T> & other) {
mat.swap(other.mat);
@@ -260,13 +296,11 @@ public:
piSwap<size_t>(cols_, other.cols_);
}
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 PIVector2D<T> & _resizeRaw(size_t r, size_t c) {
rows_ = r;
cols_ = c;
mat._resizeRaw(r*c);
mat._resizeRaw(r * c);
return *this;
}
@@ -275,19 +309,17 @@ public:
mat.clear();
}
const PIVector2D<T> & forEach(std::function<void(const T &)> f) const {
template<typename ST>
inline PIVector2D<ST> map(std::function<ST(const T & e)> f) const {
return PIVector2D<ST>(rows_, cols_, mat.map(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);
return *this;
}
PIVector2D<T> copyForEach(std::function<T(const T &)> f) const {
PIVector2D<T> ret(*this);
ret.mat = mat.copyForEach(f);
return ret;
}
PIVector2D<T> & forEachInplace(std::function<T(const T &)> f) {
mat.forEachInplace(f);
return *this;
}
protected:
size_t rows_, cols_;
@@ -296,8 +328,8 @@ protected:
template<typename T>
inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
s.setControl(0, true);
inline PICout operator<<(PICout s, const PIVector2D<T> & v) {
s.saveAndSetControls(0);
s << "{";
for (size_t i = 0; i < v.rows(); ++i) {
s << "{ ";
@@ -306,11 +338,11 @@ inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
if (j < v.cols() - 1) s << ", ";
}
s << " }";
if (i < v.rows() - 1) s << PICoutManipulators::NewLine ;
if (i < v.rows() - 1) s << PICoutManipulators::NewLine;
}
if (v.isEmpty()) s << "{ }";
s << "}";
s.restoreControl();
s.restoreControls();
return s;
}

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