254 Commits

Author SHA1 Message Date
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
251 changed files with 17995 additions and 6984 deletions

3
.gitignore vendored
View File

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

View File

@@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip)
set(pip_MAJOR 2)
set(pip_MINOR 28)
set(pip_REVISION 1)
set(pip_MINOR 39)
set(pip_REVISION 0)
set(pip_SUFFIX )
set(pip_COMPANY SHS)
set(pip_DOMAIN org.SHS)
@@ -284,7 +284,7 @@ endif()
if(APPLE)
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
endif()
if ((NOT DEFINED LIBPROJECT) AND (DEFINED ANDROID_PLATFORM))
if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
include_directories(${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include)
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include")
@@ -320,7 +320,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()
@@ -451,7 +451,7 @@ if (NOT CROSSTOOLS)
#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)
endif()
else()
@@ -550,16 +550,29 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
include(PIPDocumentation)
find_package(Doxygen)
if(DOXYGEN_FOUND)
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_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
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)
@@ -567,8 +580,8 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
list(APPEND DOXY_INPUT "\"${F}\"")
endforeach(F)
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\"")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${DOXY_INPUT}")
string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS};DOXYGEN;PIOBJECT;PIOBJECT_SUBCLASS")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${PIP_INCLUDES}")
string(REPLACE ";" " " DOXY_DEFINES "${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()

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://shs.tools/pip/html/en/index.html)
[🇺🇸 Qt-help](https://shs.tools/pip/pip_en.qch)
[🇷🇺 Онлайн документация](https://shs.tools/pip/html/ru/index.html)
[🇷🇺 Qt-help](https://shs.tools/pip/pip_ru.qch)

View File

@@ -71,6 +71,10 @@ 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()

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
@@ -2232,12 +2284,6 @@ EXTERNAL_GROUPS = 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
#---------------------------------------------------------------------------
# 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

@@ -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

@@ -3,7 +3,7 @@ void _() {
//! [0]
class SomeIO: public PIIODevice {
PIIODEVICE(SomeIO)
PIIODEVICE(SomeIO, "myio")
public:
SomeIO(): PIIODevice() {}
protected:
@@ -19,9 +19,8 @@ protected:
// 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
// parse full_path and configure device here
}
};
REGISTER_DEVICE(SomeIO)

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

BIN
doc/pip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

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

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

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@
#include "picompress.h"
#ifdef PIP_COMPRESS
# ifdef FREERTOS
# ifdef ESP_PLATFORM
# include "esp32/rom/miniz.h"
# define compress2 mz_compress2
# define Z_OK MZ_OK

View File

@@ -23,6 +23,7 @@
# include <fcntl.h>
# include <termios.h>
#else
# include <wingdi.h>
# include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000
@@ -62,7 +63,7 @@ PIScreen::SystemConsole::SystemConsole() {
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else
# ifdef FREERTOS
# ifdef MICRO_PIP
w = 80;
h = 24;
# else
@@ -108,16 +109,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;
@@ -144,7 +142,7 @@ void PIScreen::SystemConsole::resize(int w, int h) {
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;
@@ -221,14 +219,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();
}
}
@@ -297,32 +296,32 @@ void PIScreen::SystemConsole::newLine() {
}
#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

View File

@@ -689,13 +689,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
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

@@ -19,9 +19,10 @@
#include "piincludes_p.h"
#include "piterminal.h"
#include "pisharedmemory.h"
#ifndef FREERTOS
#ifndef MICRO_PIP
#ifdef WINDOWS
# include <windows.h>
# include <wingdi.h>
# include <wincon.h>
# include <winuser.h>
#else
@@ -238,9 +239,9 @@ void PITerminal::write(PIKbdListener::KeyEvent ke) {
else {
PIByteArray ba;
#ifdef WINDOWS
ba << uchar(PIChar(ke.key).toConsole1Byte());
ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
#else
ba = PIString(PIChar(ke.key)).toUTF8();
ba = PIString(PIChar((ushort)ke.key)).toUTF8();
#endif
write(ba);
}
@@ -811,11 +812,12 @@ bool PITerminal::initialize() {
//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;
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(PRIVATE->shell.dataAscii(), argv);
execvp(argv[0], argv);
delete[] argv[0];
delete[] argv;
exit(0);
@@ -917,4 +919,4 @@ bool PITerminal::resize(int cols, int rows) {
return ret;
}
#endif // FREERTOS
#endif // MICRO_PIP

View File

@@ -128,7 +128,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar(0));
ps.fill(PIChar());
tba.clear();
tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk);

View File

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

View File

@@ -1,5 +1,5 @@
/*! @file pifft_p.h
* @brief Class for FFT, IFFT and Hilbert transformations
/*! \file pifft_p.h
* \brief Class for FFT, IFFT and Hilbert transformations
*/
/*
PIP - Platform Independent Primitives

View File

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

View File

@@ -23,7 +23,7 @@
#endif
/** \class PIEthUtilBase
* @brief Base class for ethernet utils
* \brief Base class for ethernet utils
*
* \section PIEthUtilBase_synopsis Synopsis
* %PIEthUtilBase provides crypt layer for derived classes:

View File

@@ -28,7 +28,7 @@
#endif
/** \class PIStreamPacker
* @brief Simple packet wrap aroud any PIIODevice
* \brief Simple packet wrap aroud any PIIODevice
*
* \section PIStreamPacker_synopsis Synopsis
* %PIStreamPacker provides simple pack/unpack logic for any data packets.
@@ -68,6 +68,13 @@ void PIStreamPacker::setCryptSizeEnabled(bool on) {
}
void PIStreamPacker::clear() {
packet.clear();
packet_size = -1;
stream.clear();
}
void PIStreamPacker::send(const PIByteArray & data) {
if (data.isEmpty()) return;
PIByteArray cd;
@@ -94,31 +101,12 @@ void PIStreamPacker::send(const PIByteArray & data) {
hdr << int(cd.size_s());
cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = true;
prog_s.bytes_all = data.size_s();
prog_s.bytes_current = 0;
prog_s.progress = 0.;
prog_s_mutex.unlock();
}
for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else part = PIByteArray(cd.data(pst), max_packet_size);
//piCout << "send" << part.size();
sendRequest(part);
pst += max_packet_size;
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.bytes_current += part.size_s();
prog_s.progress = (double)prog_s.bytes_current / prog_s.bytes_all;
prog_s_mutex.unlock();
}
}
if (pcnt > 1) {
prog_s_mutex.lock();
prog_s.active = false;
prog_s_mutex.unlock();
}
}
@@ -166,22 +154,10 @@ void PIStreamPacker::received(const PIByteArray & data) {
packet_size = sz;
if (packet_size == 0)
packet_size = -1;
else {
prog_r_mutex.lock();
prog_r.active = true;
prog_r.bytes_all = packet_size;
prog_r.bytes_current = 0;
prog_r.progress = 0.;
prog_r_mutex.unlock();
}
continue;
} else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps);
prog_r_mutex.lock();
prog_r.bytes_current = packet.size_s();
prog_r.progress = (double)prog_r.bytes_current / piMaxi(1, prog_r.bytes_all);
prog_r_mutex.unlock();
stream.remove(0, ps);
if (packet.size_s() == packet_size) {
PIByteArray cd;
@@ -211,9 +187,6 @@ void PIStreamPacker::received(const PIByteArray & data) {
}
packet.clear();
packet_size = -1;
prog_r_mutex.lock();
prog_r.active = false;
prog_r_mutex.unlock();
}
}
}
@@ -227,30 +200,3 @@ void PIStreamPacker::assignDevice(PIIODevice * dev) {
CONNECTU(dev, threadedReadEvent, this, received);
CONNECTU(this, sendRequest, dev, write);
}
PIStreamPacker::Progress PIStreamPacker::progressSend() const {
PIStreamPacker::Progress ret;
prog_s_mutex.lock();
ret = prog_s;
prog_s_mutex.unlock();
return ret;
}
PIStreamPacker::Progress PIStreamPacker::progressReceive() const {
PIStreamPacker::Progress ret;
prog_r_mutex.lock();
ret = prog_r;
prog_r_mutex.unlock();
return ret;
}
PIStreamPacker::Progress::Progress() {
active = false;
bytes_all = bytes_current = 0;
progress = 0.;
}

View File

@@ -1,6 +1,9 @@
/*! @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

View File

@@ -1,6 +1,9 @@
/*! @file picloudclient.h
* @brief PICloud Client
*/
/*! \file picloudclient.h
* \ingroup Cloud
* \~\brief
* \~english PICloud Client
* \~russian Клиент PICloud
*/
/*
PIP - Platform Independent Primitives
PICloud Client
@@ -27,11 +30,11 @@
#include "piconditionvar.h"
//! @brief PICloudClient
//! \brief PICloudClient
class PIP_CLOUD_EXPORT PICloudClient: public PIIODevice, public PICloudBase
{
PIIODEVICE(PICloudClient)
PIIODEVICE(PICloudClient, "")
public:
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudClient();
@@ -52,12 +55,15 @@ protected:
private:
EVENT_HANDLER1(void, _readed, PIByteArray &, data);
void internalDisconnect();
PIByteArray buff;
PIMutex mutex_buff;
PIMutex mutex_connect;
PIConditionVariable cond_buff;
PIConditionVariable cond_connect;
std::atomic_bool is_connected;
std::atomic_bool is_deleted;
};
#endif // PICLOUDCLIENT_H

View File

@@ -16,6 +16,37 @@
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

View File

@@ -1,6 +1,9 @@
/*! @file picloudserver.h
* @brief PICloud Server
*/
/*! \file picloudserver.h
* \ingroup Cloud
* \~\brief
* \~english PICloud Server
* \~russian Сервер PICloud
*/
/*
PIP - Platform Independent Primitives
PICloud Server
@@ -29,14 +32,14 @@
class PIP_CLOUD_EXPORT PICloudServer: public PIIODevice, public PICloudBase
{
PIIODEVICE(PICloudServer)
PIIODEVICE(PICloudServer, "")
public:
//! PICloudServer
explicit PICloudServer(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudServer();
class Client : public PIIODevice {
PIIODEVICE(PICloudServer::Client)
PIIODEVICE(PICloudServer::Client, "")
friend class PICloudServer;
public:
Client(PICloudServer * srv = nullptr, uint id = 0);
@@ -78,6 +81,7 @@ private:
PIVector<Client *> clients_;
PIMap<uint, Client *> index_clients;
PITimer ping_timer;
mutable PIMutex clients_mutex;
};

View File

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

View File

@@ -24,31 +24,39 @@
PIString PICodeInfo::EnumInfo::memberName(int value_) const {
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
if (e.value == value_)
return e.name;
return e.name.toString();
return PIString();
}
int PICodeInfo::EnumInfo::memberValue(const PIString & name_) const {
piForeachC (PICodeInfo::EnumeratorInfo & e, members)
if (e.name == name_)
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;
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;
}
PIMap<PIConstChars, PICodeInfo::ClassInfo * > * PICodeInfo::classesInfo;
PIMap<PIConstChars, PICodeInfo::EnumInfo * > * PICodeInfo::enumsInfo;
PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * PICodeInfo::accessValueFunctions;
PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * PICodeInfo::accessTypeFunctions;
bool __PICodeInfoInitializer__::_inited_ = false;
PIVariant PICodeInfo::getMemberAsVariant(const void * p, const char * class_name, const char * member_name) {
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);
AccessTypeFunction atf = accessTypeFunctions->value(class_name, (AccessTypeFunction)0);
AccessValueFunction avf = accessValueFunctions->value(class_name, (AccessValueFunction)0);
if (!atf || !avf) return PIVariant();
return PIVariant::fromValue(avf(p, member_name), PIStringAscii(atf(member_name)));
}

View File

@@ -1,6 +1,9 @@
/*! @file picodeinfo.h
* @brief C++ code info structs
*/
/*! \file picodeinfo.h
* \ingroup Code
* \~\brief
* \~english C++ code info structs
* \~russian Структуры для C++ кода
*/
/*
PIP - Platform Independent Primitives
C++ code info structs
@@ -24,7 +27,10 @@
#ifndef PICODEINFO_H
#define PICODEINFO_H
#include "piconstchars.h"
#include "pistringlist.h"
#include "pivarianttypes.h"
class PIVariant;
@@ -47,18 +53,18 @@ typedef PIByteArray(*AccessValueFunction)(const void *, const char *);
typedef const char*(*AccessTypeFunction)(const char *);
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;}
TypeInfo(const PIConstChars & n = PIConstChars(), const PIConstChars & t = PIConstChars(), PICodeInfo::TypeFlags f = 0, int b = -1) {name = n; type = t; flags = f; bits = b;}
bool isBitfield() const {return bits > 0;}
MetaMap meta;
PIString name;
PIString type;
PIConstChars name;
PIConstChars type;
PICodeInfo::TypeFlags flags;
int bits;
};
struct PIP_EXPORT FunctionInfo {
MetaMap meta;
PIString name;
PIConstChars name;
TypeInfo return_type;
PIVector<PICodeInfo::TypeInfo> arguments;
};
@@ -67,26 +73,28 @@ struct PIP_EXPORT ClassInfo {
ClassInfo() {has_name = true;}
MetaMap meta;
bool has_name;
PIString type;
PIString name;
PIStringList parents;
PIConstChars type;
PIConstChars name;
PIVector<PIConstChars> parents;
PIVector<PICodeInfo::TypeInfo> variables;
PIVector<PICodeInfo::FunctionInfo> functions;
PIVector<PICodeInfo::ClassInfo * > children_info;
};
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());}
MetaMap meta;
PIString name;
PIConstChars name;
int value;
};
struct PIP_EXPORT EnumInfo {
PIString memberName(int value) const;
int memberValue(const PIString & name) const;
PIVariantTypes::Enum toPIVariantEnum();
MetaMap meta;
PIString name;
PIConstChars name;
PIVector<PICodeInfo::EnumeratorInfo> members;
};
@@ -112,17 +120,17 @@ inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
if (!v.parents.isEmpty()) {
s << ": ";
bool first = true;
piForeachC (PIString & i, v.parents) {
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) {
for (const auto & a: i.arguments) {
if (fa) fa = false;
else s << ", ";
s << a;
@@ -131,7 +139,7 @@ inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
}
if (!v.functions.isEmpty() && !v.variables.isEmpty())
s << "\n";
piForeachC (TypeInfo & i, v.variables) {
for (const auto & i: v.variables) {
s << PICoutManipulators::Tab << i << " Meta" << i.meta << ";\n";
}
s << "}\n";
@@ -142,7 +150,7 @@ inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
s.setControl(0, true);
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 << ", ";
@@ -153,21 +161,21 @@ inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
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;
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::ClassInfo * > * classesInfo;
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::EnumInfo * > * enumsInfo;
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
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);
AccessValueFunction af = 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);
AccessTypeFunction af = accessTypeFunctions->value(class_name, (AccessTypeFunction)0);
if (!af) return "";
return af(member_name);
}
@@ -188,10 +196,10 @@ 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>;
PICodeInfo::classesInfo = new PIMap<PIConstChars, PICodeInfo::ClassInfo * >;
PICodeInfo::enumsInfo = new PIMap<PIConstChars, PICodeInfo::EnumInfo * >;
PICodeInfo::accessValueFunctions = new PIMap<PIConstChars, PICodeInfo::AccessValueFunction>;
PICodeInfo::accessTypeFunctions = new PIMap<PIConstChars, PICodeInfo::AccessTypeFunction>;
}
static bool _inited_;
};

View File

@@ -16,6 +16,37 @@
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.
//!
//! \~russian
//! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg.
//!
//! \~\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

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

View File

@@ -1,6 +1,9 @@
/*! @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

View File

@@ -1,6 +1,10 @@
/*! @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
@@ -19,6 +23,37 @@
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
@@ -26,8 +61,16 @@
#include "pip_compress_export.h"
#include "pibytearray.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

@@ -16,6 +16,37 @@
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

@@ -21,11 +21,12 @@
#ifndef WINDOWS
# include <termios.h>
#else
# include <wingdi.h>
# include <wincon.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_)"
@@ -322,12 +323,18 @@ void PIKbdListener::readKeyboard() {
for (int i = 0; i < PRIVATE->ret; ++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;*/
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) ke.key = PIChar::fromConsole(rc[0]).unicode16Code();
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

View File

@@ -1,6 +1,9 @@
/*! @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
@@ -25,7 +28,7 @@
#include "pithread.h"
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5);
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); // TODO: rewrite with condvar
class PIP_EXPORT PIKbdListener: public PIThread
@@ -181,20 +184,20 @@ public:
//! \{
//! \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
//! \{
//! \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
//! \}

View File

@@ -1,6 +1,9 @@
/*! @file piscreen.h
* @brief Console GUI class
*/
/*! \file piscreen.h
* \ingroup Console
* \~\brief
* \~english Console tiling manager
* \~russian Консольный тайловый менеджер
*/
/*
PIP - Platform Independent Primitives
Console GUI
@@ -80,23 +83,23 @@ public:
//! \{
//! \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
//! \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"
//! \}

View File

@@ -1,8 +1,9 @@
/*! @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

View File

@@ -1,6 +1,9 @@
/*! @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

View File

@@ -1,6 +1,9 @@
/*! @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

View File

@@ -1,6 +1,9 @@
/*! @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

View File

@@ -1,6 +1,9 @@
/*! @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

View File

@@ -1,6 +1,9 @@
/*! @file piterminal.h
* @brief Virtual terminal
*/
/*! \file piterminal.h
* \ingroup Console
* \~\brief
* \~english Virtual terminal
* \~russian Виртуальный терминал
*/
/*
PIP - Platform Independent Primitives
Virtual terminal

View File

@@ -0,0 +1,34 @@
/*
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 ssize_t minAlloc = 64;
ssize_t _PIContainerConstantsBase::calcMinCountPoT(ssize_t szof) {
ssize_t ret = 0, 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,12 +1,20 @@
/*! @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
Base macros for generic containers
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
@@ -37,87 +45,140 @@
#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
#ifdef DOXYGEN
/*!@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
#include <algorithm>
#include <functional>
template <typename C>
struct _reverse_wrapper {
C & c_;
_reverse_wrapper(C & c): c_(c) {}
_reverse_wrapper(const C & c): c_(const_cast<C&>(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(); }
private:
C & c_;
};
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 ssize_t calcMinCountPoT(ssize_t szof);
};
template<typename T>
class _PIContainerConstants {
public:
static ssize_t minCountPoT() {static ssize_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,6 +1,6 @@
/*
PIP - Platform Independent Primitives
Module includes
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
@@ -16,6 +16,166 @@
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
@@ -28,4 +188,5 @@
#include "pistack.h"
#include "pivector2d.h"
#endif // PICONTAINERSMODULE_H

View File

@@ -1,8 +1,17 @@
/*! @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
@@ -28,39 +37,165 @@
#include "picontainers.h"
//! \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 𝓞(1)
//! - Insertion or removal of elements at the end or begin - amortized constant 𝓞(1)
//! - Insertion or removal of elements - linear in the distance to the end of the array 𝓞(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 следующая:
//! - Произвольный доступ — постоянная 𝓞(1)
//! - Вставка и удаление элементов в конце или начале — амортизированная постоянная 𝓞(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n)
//!
//! \~\sa \a PIVector, \a PIMap
template <typename T>
class PIDeque {
public:
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(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
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);
}
//! \~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): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
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());
}
//! \~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): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
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 PIDeque(size_t pid_size, const T & e = T()): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(pid_size, f);
resize(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): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIDeque(PIDeque<T> && other): pid_data(other.pid_data), pid_size(other.pid_size), pid_rsize(other.pid_rsize), pid_start(other.pid_start) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
other._reset();
}
inline virtual ~PIDeque() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
@@ -69,161 +204,931 @@ public:
_reset();
}
//! \~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);
alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
return *this;
}
//! \~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 T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline iterator & operator ++() {
++pos;
return *this;
}
inline iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline iterator & operator --() {
--pos;
return *this;
}
inline iterator operator --(int) {
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 const T & operator ->() const {return (*parent)[pos];}
inline const_iterator & operator ++() {
++pos;
return *this;
}
inline const_iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline const_iterator & operator --() {
--pos;
return *this;
}
inline const_iterator operator --(int) {
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 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) {
auto tmp = *this;
--*this;
return tmp;
}
inline reverse_iterator & operator --() {
++pos;
return *this;
}
inline reverse_iterator operator --(int) {
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 const T & operator ->() const {return (*parent)[pos];}
inline const_reverse_iterator & operator ++() {
--pos;
return *this;
}
inline const_reverse_iterator operator ++(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline const_reverse_iterator & operator --() {
++pos;
return *this;
}
inline const_reverse_iterator operator --(int) {
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;
}
};
//! \~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);}
//! \~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 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);}
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 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 (ssize_t i = pid_start; i < pid_start + (ssize_t)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 (ssize_t i = pid_start; i < pid_start + (ssize_t)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 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 (ssize_t i = pid_start + start; i < pid_start + (ssize_t)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;
}
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, size_t start = 0) const {
int ec = 0;
for (size_t i = pid_start; i < pid_start + pid_size; ++i)
if (v == pid_data[i]) ++ec;
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) ++ec;
}
return ec;
}
inline ssize_t indexOf(const T & v) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i)
if (v == pid_data[i])
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, size_t start = 0) const {
int ec = 0;
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) ++ec;
}
return ec;
}
inline ssize_t 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])
//! \~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, size_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) {
return i - pid_start;
}
}
return -1;
}
//! \~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, size_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) {
return i - pid_start;
}
}
return -1;
}
//! \~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 = pid_start + start; i >= pid_start; --i) {
if (e == pid_data[i]) {
return i - 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 = pid_start + start; i >= pid_start; --i) {
if (test(pid_data[i])) {
return i - 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>
@@ -241,65 +1146,121 @@ public:
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);}
//! \~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 & f) {
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) {
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 < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size;
if (new_size == 0)
if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2;
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc(new_size, true);
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);
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, e);
}
}
return *this;
}
inline PIDeque<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 PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size;
if (new_size == 0)
if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2;
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc(new_size, true);
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i)
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f(i));
}
}
return *this;
}
@@ -314,72 +1275,161 @@ public:
if (new_size < pid_size) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size-new_size));
}
alloc(new_size, true);
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);
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);
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));
}
} else {
alloc(pid_size + 1, false, -1);
if (index > 0)
alloc_backward(pid_size + 1, -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));
}
} 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)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
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));
}
} else {
alloc_backward(pid_size + 1, -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(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);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
ssize_t os = pid_size - index;
alloc_forward(pid_size + v.pid_size);
if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start + v.pid_size])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else {
alloc_backward(pid_size + v.pid_size, -v.pid_size);
if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (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) {
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
ssize_t os = pid_size - index;
alloc_forward(pid_size + init_list.size());
if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start + init_list.size()])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
}
} else {
alloc_backward(pid_size + init_list.size(), -init_list.size());
if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (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) {
@@ -389,15 +1439,24 @@ public:
size_t os = pid_size - index - count;
deleteT(&(pid_data[index + pid_start]), count);
if (os <= index) {
if (os > 0) memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
}
} else {
if (index > 0) memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
if (index > 0) {
memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
}
pid_start += count;
}
pid_size -= count;
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<size_t>(pid_size, other.pid_size);
@@ -405,13 +1464,114 @@ public:
piSwap<ssize_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;
}
//! \~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;
}
//! \~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() {
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(llong pid_size) {
llong ns = size_s() + pid_size;
if (ns <= 0) clear();
@@ -419,139 +1579,708 @@ public:
return *this;
}
inline PIDeque<T> & removeOne(const T & v) {
for (size_t i = 0; i < pid_size; ++i)
if (pid_data[i + pid_start] == v) {
//! \~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) {
//! \~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) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (pid_data[i + pid_start] == e) {
remove(i);
--i;
}
}
return *this;
}
inline PIDeque<T> & push_back(const T & v) {
alloc(pid_size + 1, true);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(pid_data + pid_start + pid_size - 1, v);
//! \~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) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (test(pid_data[i + pid_start])) {
remove(i);
--i;
}
}
return *this;
}
inline PIDeque<T> & push_back(T && v) {
alloc(pid_size + 1, true);
//! \~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, std::move(v));
elementNew(pid_data + pid_start + pid_size - 1, 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);
//! \~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(e));
return *this;
}
//! \~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) {
size_t ps = pid_size;
alloc(pid_size + t.pid_size, true);
newT(pid_data + ps + pid_start, t.pid_data + t.pid_start, t.pid_size);
alloc_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) {
#ifndef NDEBUG
if (&v == this) {
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
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));}
//! \~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) {
insert(0, 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) {
insert(0, 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) {
insert(0, v);
return *this;
}
//! \~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) {
insert(0, init_list);
return *this;
}
//! \~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 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
//! 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;
resize(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;
remove(0);
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() {
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() {
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>
PIDeque<ST> toType() const {
inline PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size);
for (uint i = 0; i < pid_size; ++i)
for (size_t i = 0; i < pid_size; ++i) {
ret[i] = ST(pid_data[i + pid_start]);
}
return ret;
}
const PIDeque<T> & forEach(std::function<void(const T &)> f) const {
for (uint i = 0; i < pid_size; ++i)
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]);
//! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `test`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `test`.
//! \~\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;
}
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]);
//! \~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 С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>
PIDeque<ST> toType(std::function<ST(const T &)> f) const {
inline PIDeque<ST> map(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret; ret.reserve(pid_size);
for (uint i = 0; i < pid_size; ++i)
ret << f(pid_data[i + pid_start]);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret << f(pid_data[i]);
}
return ret;
}
inline PIDeque<PIDeque<T>> reshape(size_t rows, size_t cols, int order = byRow) const {
//! \~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 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 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;
#ifndef NDEBUG
if (rows*cols != pid_size) {
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
}
#endif
assert(rows*cols == pid_size);
ret.resize(rows);
if (order == byRow) {
for (size_t r = 0; r < rows; r++)
if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) {
ret[r] = PIDeque<T>(&(pid_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++)
for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c*rows + r];
}
}
}
return ret;
}
//! \~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> reshape(int order = byRow) const {
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();
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);
}
private:
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
inline size_t asize(ssize_t s) {
if (s <= 0) return 0;
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s))
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) {
return pid_rsize + pid_rsize;
ssize_t t = 0, s_ = s - 1;
}
ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
while (s_ >> t)
++t;
return (1 << t);
@@ -577,8 +2306,9 @@ private:
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i)
for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]);
}
}
}
template<typename T1 = T, typename std::enable_if<
@@ -615,7 +2345,7 @@ private:
if ((uchar*)pid_data != 0) free((uchar*)pid_data);
pid_data = 0;
}
inline void checkMove(bool direction) {
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))) {
@@ -634,11 +2364,10 @@ private:
}
}
}
inline void alloc(size_t new_size, bool direction, ssize_t start_offset = 0) { // direction == true -> alloc forward
if (direction) {
inline void alloc_forward(size_t new_size) { // direction == true -> alloc forward
if (pid_start + new_size <= pid_rsize) {
pid_size = new_size;
checkMove(direction);
checkMove();
return;
}
pid_size = new_size;
@@ -646,16 +2375,23 @@ private:
if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
T * p_d = (T*)(realloc((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;
}
} else {
}
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
size_t as;
if (pid_start + start_offset < 0)
if (pid_start + start_offset < 0) {
as = asize(pid_rsize - start_offset);
else as = pid_rsize;
} else {
as = pid_rsize;
}
if (as > pid_rsize) {
T * td = (T*)(malloc(as * sizeof(T)));
ssize_t ns = pid_start + as - pid_rsize;
@@ -670,8 +2406,7 @@ private:
}
pid_start += start_offset;
pid_size = new_size;
checkMove(direction);
}
checkMove();
}
T * pid_data;
@@ -681,10 +2416,24 @@ private:
#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;}
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
//! \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();
@@ -692,15 +2441,15 @@ inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1)
s << ", ";
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControl();
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,5 +1,5 @@
/** \class PIMap
* @brief Associative array
* \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
@@ -9,97 +9,97 @@
* \a makeIterator() and \a makeReverseIterator().
* \fn PIMap::PIMap();
* @brief Contructs an empty map
* \brief Contructs an empty map
* \fn PIMap::PIMap(const PIMap & other);
* @brief Contructs a copy of "other"
* \brief Contructs a copy of "other"
* \fn PIMap & PIMap::operator =(const PIMap & other);
* @brief Copy operator
* \brief Copy operator
* \fn PIMap::PIMap(const PIMap & other);
* @brief Contructs a copy of "other"
* \brief Contructs a copy of "other"
* \fn PIMapIterator PIMap::makeIterator() const
* @brief Returns PIMapIterator for this map
* \brief Returns PIMapIterator for this map
* \fn PIMapIterator PIMap::makeReverseIterator() const
* @brief Returns reverse PIMapIterator for this map
* \brief Returns reverse PIMapIterator for this map
* \fn size_t PIMap::size() const
* @brief Returns entries count
* \brief Returns entries count
* \fn int PIMap::size_s() const
* @brief Returns entries count
* \brief Returns entries count
* \fn size_t PIMap::length() const
* @brief Returns entries count
* \brief Returns entries count
* \fn bool PIMap::isEmpty() const
* @brief Returns if map is empty
* \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.
* \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().
* \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 []
* \brief Equivalent to operator []
* \fn const T PIMap::at(const Key & key) const
* @brief Equivalent to operator []
* \brief Equivalent to operator []
* \fn PIMap & PIMap::operator <<(const PIMap & other)
* @brief Insert all etries of "other" to this map. Override existing values.
* \brief Insert all etries of "other" to this map. Override existing values.
* \fn bool PIMap::operator ==(const PIMap & t) const
* @brief Compare operator
* \brief Compare operator
* \fn bool PIMap::operator !=(const PIMap & t) const
* @brief Compare operator
* \brief Compare operator
* \fn bool PIMap::contains(const Key & key) const
* @brief Returns "true" if map contains entry with key "key"
* \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
* \brief Reserve space for "new_size" entries
* \fn PIMap & PIMap::removeOne(const Key & key)
* @brief Remove entry with key "key"
* \brief Remove entry with key "key"
* \fn PIMap & PIMap::remove(const Key & key)
* @brief Equivalent \a removeOne(key)
* \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::erase(const Key & key)
* @brief Equivalent \a removeOne(key)
* \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::clear()
* @brief Clear map
* \brief Clear map
* \fn void PIMap::swap(PIMap & other)
* @brief Swap map with "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"
* \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".
* \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
* \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".
* \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
* \brief Returns all keys as PIVector
* */
@@ -107,7 +107,7 @@
/** \class PIMapIterator
* @brief Helper class to iterate over PIMap
* \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.
@@ -164,24 +164,24 @@
* \endcode
* \fn PIMapIterator(const PIMap & map, bool reverse = false)
* @brief Contructs iterator for "map". Current position is invalid.
* \brief Contructs iterator for "map". Current position is invalid.
* \fn const Key & PIMapIterator::key() const
* @brief Returns current entry key
* \brief Returns current entry key
* \fn const T & PIMapIterator::value() const
* @brief Returns current entry value
* \brief Returns current entry value
* \fn T & PIMapIterator::valueRef() const
* @brief Returns reference to current entry value
* \brief Returns reference to current entry value
* \fn bool PIMapIterator::hasNext()
* @brief Returns if iterator can jump to next entry
* \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.
* \brief Jump to next entry and return if new position is valid.
* \fn void PIMapIterator::reset()
* @brief Reset iterator to initial position.
* \brief Reset iterator to initial position.
* */

View File

@@ -1,5 +1,5 @@
/*! @file pimap.h
* @brief Associative array with custom types of key and value
/*! \file pimap.h
* \brief Associative array with custom types of key and value
*
* This file declares PIMap
*/
@@ -107,6 +107,7 @@ 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);}
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;}
@@ -125,6 +126,7 @@ 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);}
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;}
@@ -206,6 +208,11 @@ public:
const T at(const Key & key) const {return (*this)[key];}
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;}

View File

@@ -1,8 +1,17 @@
/*! @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
@@ -25,31 +34,111 @@
#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 Класс, который позволяет хранить два разнородных объекта как единое целое.
//! \~\}
//! \details
//! \~english
//! \~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).
PIPair(std::tuple<Type0, Type1> tuple) {
first = std::get<0>(tuple);
second = std::get<1>(tuple);
}
//! \~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.setControl(0, true);
s << "(" << v.first << ", " << v.second << ")";
s.restoreControl();
return s;
}
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
//! \~russian Создает \a PIPair выводя типы из аргументов.
//! \~\details
//! \~\code
//! auto p = createPIPair(1, 'a');
//! piCout << p; // (1, a)
//! \endcode
template< class T1, class T2 >
PIPair<T1,T2> createPIPair(const T1 & f, const T2 & s) {
return PIPair<T1,T2>(f, s);
}
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
//! \~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,5 +1,5 @@
/*! @file pideque.h
* @brief Queue container
/*! \file piqueue.h
* \brief Queue container
*
* This file declare PIQueue
*/

View File

@@ -1,5 +1,5 @@
/*! @file piset.h
* @brief Set container
/*! \file piset.h
* \brief Set container
*
* This file declare PISet
*/
@@ -27,7 +27,7 @@
#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
@@ -129,16 +129,16 @@ public:
};
//! \relatesalso PISet @brief Returns unite of two sets
//! \relatesalso PISet \brief Returns unite of two sets
template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
//! \relatesalso PISet @brief Returns subtraction of two sets
//! \relatesalso PISet \brief Returns subtraction of two sets
template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;}
//! \relatesalso PISet @brief Returns unite of two sets
//! \relatesalso PISet \brief Returns unite of two sets
template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
//! \relatesalso PISet @brief Returns intersetion of two sets
//! \relatesalso PISet \brief Returns intersetion of two sets
template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;}

View File

@@ -1,5 +1,5 @@
/*! @file pistack.h
* @brief Stack container
/*! \file pistack.h
* \brief Stack container
*
* This file declare PIStack
*/

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,11 +1,20 @@
/*! @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
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
@@ -28,39 +37,165 @@
#include "picontainers.h"
//! \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 𝓞(1)
//! - Insertion or removal of elements at the end - amortized constant 𝓞(1)
//! - Insertion or removal of elements - linear in the distance to the end of the array 𝓞(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 следующая:
//! - Произвольный доступ — постоянная 𝓞(1)
//! - Вставка и удаление элементов в конце — амортизированная постоянная 𝓞(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n)
//!
//! \~\sa \a PIDeque, \a PIMap
template <typename T>
class PIVector {
public:
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(): piv_data(0), piv_size(0), piv_rsize(0) {
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): piv_data(0), piv_size(0), piv_rsize(0) {
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): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(other.piv_size);
newT(piv_data, other.piv_data, piv_size);
alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size);
}
//! \~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): piv_data(0), piv_size(0), piv_rsize(0) {
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 PIVector(size_t size, const T & e = T()): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
resize(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): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f);
resize(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): piv_data(v.piv_data), piv_size(v.piv_size), piv_rsize(v.piv_rsize) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
other._reset();
v._reset();
}
inline virtual ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
@@ -69,156 +204,921 @@ public:
_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 T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline iterator & operator ++() {
++pos;
return *this;
}
inline iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline iterator & operator --() {
--pos;
return *this;
}
inline iterator operator --(int) {
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 const T & operator ->() const {return (*parent)[pos];}
inline const_iterator & operator ++() {
++pos;
return *this;
}
inline const_iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline const_iterator & operator --() {
--pos;
return *this;
}
inline const_iterator operator --(int) {
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 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) {
auto tmp = *this;
--*this;
return tmp;
}
inline reverse_iterator & operator --() {
++pos;
return *this;
}
inline reverse_iterator operator --(int) {
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 const T & operator ->() const {return (*parent)[pos];}
inline const_reverse_iterator & operator ++() {
--pos;
return *this;
}
inline const_reverse_iterator operator ++(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline const_reverse_iterator & operator --() {
++pos;
return *this;
}
inline const_reverse_iterator operator --(int) {
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;
}
};
//! \~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);}
//! \~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 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);}
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;
//! \~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 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 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;
}
//! \~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;
}
//! \~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>
@@ -235,21 +1135,50 @@ public:
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);}
//! \~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>
@@ -265,7 +1194,18 @@ public:
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);
@@ -275,12 +1215,25 @@ public:
size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i)
elementNew(piv_data + i, f);
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, 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);
@@ -290,11 +1243,13 @@ public:
size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i)
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f(i));
}
}
return *this;
}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
@@ -308,10 +1263,25 @@ public:
alloc(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 PIVector<T> & reserve(size_t new_size) {
if (new_size <= piv_rsize) return *this;
size_t os = piv_size;
@@ -320,37 +1290,97 @@ public:
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));
}
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) {
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(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);
ssize_t os = piv_size - index;
alloc(piv_size + v.piv_size);
if (os > 0) {
memmove((void*)(&(piv_data[index + v.piv_size])), (const void*)(&(piv_data[index])), os * sizeof(T));
}
newT(piv_data + index, v.piv_data, v.piv_size);
return *this;
}
//! \~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) {
ssize_t os = piv_size - index;
alloc(piv_size + init_list.size());
if (os > 0) {
memmove((void*)(&(piv_data[index + init_list.size()])), (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) {
@@ -364,170 +1394,820 @@ public:
return *this;
}
inline void swap(PIVector<T> & other) {
piSwap<T*>(piv_data, other.piv_data);
piSwap<size_t>(piv_size, other.piv_size);
piSwap<size_t>(piv_rsize, other.piv_rsize);
//! \~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;
//! \~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;
}
//! \~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() {
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(llong add_size, const T & e = T()) {
llong ns = size_s() + add_size;
if (ns <= 0) clear();
else resize(size_t(ns));
else resize(size_t(ns), e);
return *this;
}
inline PIVector<T> & removeOne(const T & v) {
for (size_t i = 0; i < piv_size; ++i)
if (piv_data[i] == v) {
//! \~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) {
//! \~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) {
for (ssize_t i = 0; i < size_s(); ++i) {
if (piv_data[i] == e) {
remove(i);
--i;
}
}
return *this;
}
inline PIVector<T> & push_back(const T & v) {
alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, 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) {
for (ssize_t i = 0; i < size_s(); ++i) {
if (test(piv_data[i])) {
remove(i);
--i;
}
}
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 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, std::move(v));
elementNew(piv_data + piv_size - 1, 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);
//! \~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(e));
return *this;
}
//! \~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) {
size_t ps = piv_size;
alloc(piv_size + other.piv_size);
newT(piv_data + ps, other.piv_data, other.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) {
#ifndef NDEBUG
if (&v == this) {
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
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) {
insert(0, 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 PIVector<T> & push_front(T && e) {
insert(0, 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
//! 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) {
insert(0, v);
return *this;
}
//! \~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) {
insert(0, init_list);
return *this;
}
//! \~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;
if (piv_size == 0) return *this;
resize(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;}
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]);
return ret;
//! \~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() {
T e(back());
pop_back();
return e;
}
const PIVector<T> & forEach(std::function<void(const T &)> f) const {
for (uint 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;
}
PIVector<T> & forEachInplace(std::function<T(const T &)> f) {
for (uint i = 0; i < piv_size; ++i)
piv_data[i] = f(piv_data[i]);
return *this;
//! \~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() {
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>
PIVector<ST> toType(std::function<ST(const T &)> f) const {
inline PIVector<ST> toType() const {
PIVector<ST> ret; ret.reserve(piv_size);
for (uint i = 0; i < piv_size; ++i)
ret << f(piv_data[i]);
for (size_t i = 0; i < piv_size; ++i) {
ret << ST(piv_data[i]);
}
return ret;
}
inline PIVector<PIVector<T>> reshape(size_t rows, size_t cols, int order = byRow) const {
//! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `test`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `test`.
//! \~\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 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;
}
//! \~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;
}
//! \~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 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++)
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++)
for (size_t c = 0; c < cols; c++) {
ret[r][c] = piv_data[c*rows + r];
}
}
}
return ret;
}
//! \~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> reshape(int order = byRow) const {
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();
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);
}
private:
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
inline size_t asize(size_t s) {
if (s == 0) return 0;
if (piv_rsize + piv_rsize >= s && piv_rsize < s)
if (piv_rsize + piv_rsize >= s && piv_rsize < s) {
return piv_rsize + piv_rsize;
ssize_t t = 0, s_ = s - 1;
while (s_ >> t) ++t;
}
ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
while (s_ >> t)
++t;
return (1 << t);
}
template<typename T1 = T, typename std::enable_if<
@@ -551,8 +2231,9 @@ private:
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i)
for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]);
}
}
}
template<typename T1 = T, typename std::enable_if<
@@ -599,6 +2280,11 @@ private:
if (as == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
T * p_d = (T*)(realloc((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_rsize = as;
@@ -609,12 +2295,24 @@ private:
};
#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;}
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
//! \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();
@@ -622,15 +2320,16 @@ inline PICout operator <<(PICout s, const PIVector<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1)
if (i < v.size() - 1) {
s << ", ";
}
}
s << "}";
s.restoreControl();
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,5 +1,5 @@
/*! @file pivector2d.h
* @brief 2D wrapper around PIVector
/*! \file pivector2d.h
* \brief 2D wrapper around PIVector
*
* This file declares PIVector
*/
@@ -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.
@@ -275,17 +275,12 @@ public:
mat.clear();
}
const PIVector2D<T> & forEach(std::function<void(const T &)> f) const {
void forEach(std::function<void(const T &)> f) const {
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);
PIVector2D<T> & forEach(std::function<void(T &)> f) {
mat.forEach(f);
return *this;
}

View File

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

View File

@@ -1,5 +1,7 @@
/*! @file pibitarray.h
* @brief Bit array
/*! \file pibitarray.h
* \~\brief
* \~english Bit array
* \~russian Битовый массив
*/
/*
PIP - Platform Independent Primitives

View File

@@ -21,6 +21,85 @@
#include "pistringlist.h"
#include <iostream>
//! \addtogroup Core
//! \{
//! \class PIByteArray pibytearray.h
//!
//! \~\brief
//! \~english The %PIByteArray class provides an array of bytes
//! \~russian Класс %PIByteArray представляет собой массив байтов
//!
//! \~\details
//! \~english
//! %PIByteArray used to store raw bytes.
//! It can be constructed from any data and size.
//! You can use %PIByteArray as binary stream
//! to serialize/deserialize any objects and data.
//! This class based on PIDeque<uchar> and provide some handle function
//! to manipulate it.
//! \~russian
//! %PIByteArray используется для хранения байтов.
//! Он может быть сконструирован из любых даных.
//! Можно использовать %PIByteArray как потоковый объект
//! для сериализации/десериализации любых типов и данных.
//! Этот класс наследован от PIDeque<uchar> и предоставляет набор
//! удобных методов для работы с байтами.
//!
//! \~english \section PIByteArray_sec0 Usage
//! \~russian \section PIByteArray_sec0 Использование
//! \~english
//! %PIByteArray can be used to store custom data and manipulate it. There are many
//! stream operators to store/restore common types to byte array. Store operators
//! places data at the end of array, restore operators takes data from the beginning
//! of array.
//! In addition there are Hex and Base64 convertions
//! \~russian
//! %PIByteArray может быть использован для сохранения любых данных и работы с ними.
//! Он предоставляет множество операторов для сохранения/извлечения общих типов.
//! Операторы сохранения добавляют данные в конец массива, а операторы извлечения
//! берут данные из его начала.
//!
//! \~english
//! One of the major usage of %PIByteArray is stream functions. You can form binary
//! packet from many types (also dynamic types, e.g. PIVector) with one line:
//! \~russian
//! Один из основных сценариев использования %PIByteArray - это потоковый объект.
//! Можно сформировать пакет бинарных данных из многих типов (также и контейнеров,
//! например, PIVector) в одну строку:
//! \~\snippet pibytearray.cpp 0
//!
//! \~english
//! Or you can descibe stream operator of your own type and store/restore vectors of
//! your type:
//! \~russian
//! Также можно описать операторы сохранения/извлечения для собственных типов:
//! \~\snippet pibytearray.cpp 1
//!
//! \~english
//! For store/restore custom data blocks there is PIByteArray::RawData class. Stream
//! operators of this class simply store/restore data block to/from byte array:
//! \~russian
//! Для сохранения/извлечения блоков произвольных данных используется класс PIByteArray::RawData.
//! Потоковые операторы для него просто сохраняют/извлекают блоки байтов:
//! \~\snippet pibytearray.cpp 2
//!
//! \~english \section PIByteArray_sec1 Attention
//! \~russian \section PIByteArray_sec1 Внимание
//! \~english
//! Stream operator of %PIByteArray store byte array as vector, not simply append
//! content of byte array. This operators useful to transmit custom data as %PIByteArray
//! packed into parent byte array, e.g. to form packet from %PIByteArray.
//! To append one byte array to another use funtion \a append().
//! \~russian
//! Потоковый оператор для типа %PIByteArray сохраняет его как контейнер,
//! а не просто добавляет его содержимое в конец. Этот оператор полезен для управляемой
//! упаковки произвольных данных в виде %PIByteArray.
//! Для добавления содержимого одного байтового массива к другому используется
//! метов \a append().
//! \~\snippet pibytearray.cpp 3
//!
//! \}
static const uchar base64Table[64] = {
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
@@ -221,22 +300,48 @@ PIByteArray & PIByteArray::decompressRLE(uchar threshold) {
}
uchar PIByteArray::checksumPlain8() const {
//! \~\details
//! \~english
//! This is simple sum of all bytes, if "inverse" then add 1 and inverse.
//! Pseudocode:
//! \~russian
//! Это простая сумма всех байтов, если "inverse", то ещё добавляется 1 и инвертируется результат.
//! Псевдокод:
//! \~\code
//! for (i)
//! sum += at(i);
//! if (inverse) return ~(sum + 1);
//! else return sum;
//! \endcode
uchar PIByteArray::checksumPlain8(bool inverse) const {
uchar c = 0;
int sz = size_s();
for (int i = 0; i < sz; ++i)
c += at(i);
c = ~(c + 1);
if (inverse) c = ~(c + 1);
return c;
}
uint PIByteArray::checksumPlain32() const {
//! \~\details
//! \~english
//! This is sum of all bytes multiplied by index+1, if inverse then add 1 and inverse.
//! Pseudocode:
//! \~russian
//! Это простая сумма всех байтов, умноженных на индекс+1, если "inverse", то ещё добавляется 1 и инвертируется результат.
//! Псевдокод:
//! \~\code
//! for (i)
//! sum += at(i) * (i + 1);
//! if (inverse) return ~(sum + 1);
//! else return sum;
//! \endcode
uint PIByteArray::checksumPlain32(bool inverse) const {
uint c = 0;
int sz = size_s();
for (int i = 0; i < sz; ++i)
c += at(i) * (i + 1);
c = ~(c + 1);
if (inverse) c = ~(c + 1);
return c;
}

View File

@@ -1,5 +1,8 @@
/*! @file pibytearray.h
* @brief Byte array
/*! \file pibytearray.h
* \ingroup Core
* \~\brief
* \~english Byte array
* \~russian Байтовый массив
*/
/*
PIP - Platform Independent Primitives
@@ -27,85 +30,55 @@
#include "pibitarray.h"
#include "pimap.h"
#include "pivector2d.h"
#ifdef FREERTOS
# define _TYPENAME_(T) "?"
#else
# define _TYPENAME_(T) typeid(T).name()
#endif
#include <stdio.h>
class PIString;
class PIByteArray;
/*! @class PIByteArray
* @brief The PIByteArray class provides an array of bytes
* @details PIByteArray used to store raw bytes.
* It can be constructed from any data and size.
* You can use PIByteArray as binary stream
* to serialize/deserialize any objects and data.
* This class based on PIDeque<uchar> and provide some handle function
* to manipulate it.
*
* @section PIByteArray_sec0 Usage
* %PIByteArray can be used to store custom data and manipulate it. There are many
* stream operators to store/restore common types to byte array. Store operators
* places data at the end of array, restore operators takes data from the beginning
* of array.
* In addition there are Hex and Base64 convertions
*
* One of the major usage of %PIByteArray is stream functions. You can form binary
* packet from many types (also dynamic types, e.g. PIVector) with one line:
* @snippet pibytearray.cpp 0
*
* Or you can descibe stream operator of your own type and store/restore vectors of
* your type:
* @snippet pibytearray.cpp 1
*
* For store/restore custom data blocks there is PIByteArray::RawData class. Stream
* operators of this class simply store/restore data block to/from byte array.
* @snippet pibytearray.cpp 2
*
* @section PIByteArray_sec1 Attention
* Stream operator of %PIByteArray store byte array as vector, not simply append
* content of byte array. This operators useful to transmit custom data as %PIByteArray
* packed into parent byte array, e.g. to form packet from %PIByteArray.
* To append one byte array to another use funtion \a append().
* @snippet pibytearray.cpp 3
*
*
*/
class PIP_EXPORT PIByteArray: public PIDeque<uchar>
{
public:
//! Constructs an empty byte array
//! \~english Constructs an empty byte array
//! \~russian Создает пустой байтовый массив
PIByteArray() {;}
//! \~english Constructs copy of byte array "o"
//! \~russian Создает копию байтового массива "o"
PIByteArray(const PIByteArray & o): PIDeque<uchar>(o) {}
//! \~english Constructs copy of byte array "o"
//! \~russian Создает копию байтового массива "o"
PIByteArray(const PIDeque<uchar> & o): PIDeque<uchar>(o) {}
PIByteArray(PIByteArray && o): PIDeque<uchar>(std::move(o)) {}
//! Constructs 0-filled byte array with size "size"
//! \~english Constructs 0-filled byte array with size "size"
//! \~russian Создает заполненный "0" байтовый массив размером "size"
PIByteArray(const uint size) {resize(size);}
//! Constructs byte array from data "data" and size "size"
//! \~english Constructs byte array from data "data" and size "size"
//! \~russian Создает байтовый массив из данных по указателю "data" размером "size"
PIByteArray(const void * data, const uint size): PIDeque<uchar>((const uchar*)data, size_t(size)) {}
//! Constructs byte array with size "size" filled by "t"
//! \~english Constructs byte array with size "size" filled by "t"
//! \~russian Создает заполненный "t" байтовый массив размером "size"
PIByteArray(const uint size, uchar t): PIDeque<uchar>(size, t) {}
//! Help struct to store/restore custom blocks of data to/from PIByteArray
//! \~english Help struct to store/restore custom blocks of data to/from PIByteArray
//! \~russian Вспомогательная структура для сохранения/извлечения произвольного блока данных в/из байтового массива
struct RawData {
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
public:
//! Constructs data block
//! \~english Constructs data block
//! \~russian Создает блок данных
RawData(void * data = 0, int size = 0) {d = data; s = size;}
RawData(const RawData & o) {d = o.d; s = o.s;}
//! Constructs data block
//! \~english Constructs data block
//! \~russian Создает блок данных
RawData(const void * data, const int size) {d = const_cast<void * >(data); s = size;}
RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
private:
@@ -113,16 +86,27 @@ public:
int s;
};
//! Return resized byte array
//! \~english Return resized byte array
//! \~russian Возвращает копию байтового массива с измененным размером
PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;}
//! Convert data to Base 64 and return this byte array
//! \~english Return sub-array starts from "index" and has "count" or less bytes
//! \~russian Возвращает подмассив с данными от индекса "index" и размером не более "count"
PIByteArray getRange(size_t index, size_t count) const {
return PIDeque<uchar>::getRange(index, count);
}
//! \~english Convert data to Base 64 and return this byte array
//! \~russian Преобразует данные в Base 64 и возвращает текущий массив
PIByteArray & convertToBase64();
//! Convert data from Base 64 and return this byte array
//! \~english Convert data from Base 64 and return this byte array
//! \~russian Преобразует данные из Base 64 и возвращает текущий массив
PIByteArray & convertFromBase64();
//! Return converted to Base 64 data
//! \~english Return converted to Base 64 data
//! \~russian Возвращает копию байтового массива, преобразованного в Base 64
PIByteArray toBase64() const;
PIByteArray & compressRLE(uchar threshold = 192);
@@ -130,36 +114,40 @@ public:
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressRLE(threshold); return ba;}
PIByteArray decompressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.decompressRLE(threshold); return ba;}
//! \~english Return string representation of data, each byte in "base" base, separated by spaces
//! \~russian Возвращает текстовое представление байтового массива, каждый байт в "base" системе, с пробелами
PIString toString(int base = 16) const;
//! Returns a hex encoded copy of the byte array.
//! \~english
//! Returns a hex encoded copy of the byte array, without spaces.
//! The hex encoding uses the numbers 0-9 and the letters a-f.
//! \~russian
//! Возвращает шестнадцатеричное представление массива, без пробелов.
//! Оно использует цифры 0-9 и буквы a-f.
PIString toHex() const;
//! Add to the end data "data" with size "size"
//! \~english Add to the end data "data" with size "size"
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
PIByteArray & append(const void * data_, int size_) {uint ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this;}
//! Add to the end byte array "data"
//! \~english Add to the end byte array "data"
//! \~russian Добавляет в конец массива содержимое массива "data"
PIByteArray & append(const PIByteArray & data_) {uint ps = size(); enlarge(data_.size_s()); memcpy(data(ps), data_.data(), data_.size()); return *this;}
//! Add to the end "t"
//! \~english Add to the end "t"
//! \~russian Добавляет в конец массива байт "t"
PIByteArray & append(uchar t) {push_back(t); return *this;}
//! Returns 8-bit checksum
//! sum all bytes, add 1, inverse
//! Pseudocode:
//! sum += at(i);
//! return ~(sum + 1)
uchar checksumPlain8() const;
//! \~english Returns 8-bit checksum
//! \~russian Возвращает 8-битную контрольную сумму
uchar checksumPlain8(bool inverse = true) const;
//! Returns 32-bit checksum
//! sum all bytes multiplyed by index+1, add 1, inverse
//! Pseudocode:
//! sum += at(i) * (i + 1);
//! return ~(sum + 1)
uint checksumPlain32() const;
//! \~english Returns 32-bit checksum
//! \~russian Возвращает 32-битную контрольную сумму
uint checksumPlain32(bool inverse = true) const;
//! Returns hash
//! \~english Returns hash of content
//! \~russian Возвращает хэш содержимого
uint hash() const;
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
@@ -172,7 +160,8 @@ public:
static PIByteArray fromHex(PIString str);
//! Return converted from Base 64 data
//! \~english Return converted from Base 64 data
//! \~russian Возвращает массив из Base 64 представления
static PIByteArray fromBase64(const PIByteArray & base64);
static PIByteArray fromBase64(const PIString & base64);
@@ -187,43 +176,58 @@ public:
};
//! \relatesalso PIByteArray @brief Byte arrays compare operator
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
for (uint i = 0; i < v0.size(); ++i)
if (v0[i] != v1[i])
return v0[i] < v1[i];
return false;
if (v0.isEmpty()) return false;
return memcmp(v0.data(), v1.data(), v0.size()) < 0;
}
return v0.size() < v1.size();
}
//! \relatesalso PIByteArray @brief Byte arrays compare operator
inline bool operator ==(PIByteArray & f, PIByteArray & s) {
if (f.size_s() != s.size_s())
return false;
for (int i = 0; i < f.size_s(); ++i)
if (f[i] != s[i])
return false;
return true;
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator >(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return false;
return memcmp(v0.data(), v1.data(), v0.size()) > 0;
}
return v0.size() > v1.size();
}
//! \relatesalso PIByteArray @brief Byte arrays compare operator
inline bool operator !=(PIByteArray & f, PIByteArray & s) {
if (f.size_s() != s.size_s())
return true;
for (int i = 0; i < f.size_s(); ++i)
if (f[i] != s[i])
return true;
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator ==(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return true;
return memcmp(v0.data(), v1.data(), v0.size()) == 0;
}
return false;
}
//! \relatesalso PIByteArray
//! \~english Byte arrays compare operator
//! \~russian Оператор сравнения
inline bool operator !=(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) {
if (v0.isEmpty()) return false;
return memcmp(v0.data(), v1.data(), v0.size()) != 0;
}
return true;
}
#ifdef PIP_STD_IOSTREAM
//! \relatesalso PIByteArray @brief Output to std::ostream operator
//! \relatesalso PIByteArray \brief Output to std::ostream operator
inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);
#endif
//! \relatesalso PIByteArray @brief Output to PICout operator
//! \relatesalso PIByteArray
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
PIP_EXPORT PICout operator <<(PICout s, const PIByteArray & ba);
@@ -232,16 +236,24 @@ PIP_EXPORT PICout operator <<(PICout s, const PIByteArray & ba);
// store operators for basic types
//! \relatesalso PIByteArray @brief Store operator
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const bool v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray @brief Store operator
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const char v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray @brief Store operator
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const uchar v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray @brief Store operator for any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Store operator for any trivial copyable type
//! \~russian Оператор сохранения для тривиальных типов
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray::StreamRef operator <<(PIByteArray & s, const T & v) {
int os = s.size_s();
@@ -250,10 +262,14 @@ inline PIByteArray::StreamRef operator <<(PIByteArray & s, const T & v) {
return s;
}
//! \relatesalso PIByteArray @brief Store operator, see \ref PIByteArray_sec1 for details
//! \relatesalso PIByteArray
//! \~english Store operator, see \ref PIByteArray_sec1 for details
//! \~russian Оператор сохранения, подробнее в \ref PIByteArray_sec1
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v);
//! \relatesalso PIByteArray @brief Store operator, see \ref PIByteArray_sec1 for details
//! \relatesalso PIByteArray
//! \~english Store operator, see \ref PIByteArray_sec1 for details
//! \~russian Оператор сохранения, подробнее в \ref PIByteArray_sec1
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {
int os = s.size_s();
if (v.s > 0) {
@@ -263,7 +279,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v
return s;
}
//! \relatesalso PIByteArray @brief Store operator for PIVector of any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector of any trivial copyable type
//! \~russian Оператор сохранения для PIVector тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
@@ -285,7 +303,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Store operator for PIDeque of any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Store operator for PIDeque of any trivial copyable type
//! \~russian Оператор сохранения для PIDeque тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
@@ -307,7 +327,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Store operator for PIVector2D of any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector2D of any trivial copyable type
//! \~russian Оператор сохранения для PIVector2D тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
@@ -328,10 +350,14 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Store operator
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
//! \relatesalso PIPair @brief Store operator
//! \relatesalso PIPair
//! \~english Store operator
//! \~russian Оператор сохранения
template<typename Type0, typename Type1>
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
@@ -341,20 +367,28 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v
// restore operators for basic types
//! \relatesalso PIByteArray @brief Restore operator
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, bool & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray @brief Restore operator
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray @brief Restore operator
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray @brief Restore operator for any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Restore operator for any trivial copyable type
//! \~russian Оператор извлечения для тривиальных типов
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
if (s.size() < sizeof(v)) {
printf("error with %s\n", _TYPENAME_(T));
printf("error with %s\n", __PIP_TYPENAME__(T));
assert(s.size() >= sizeof(v));
}
memcpy((void*)(&v), s.data(), sizeof(v));
@@ -362,10 +396,14 @@ inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
return s;
}
//! \relatesalso PIByteArray @brief Restore operator, see \ref PIByteArray_sec1 for details
//! \relatesalso PIByteArray
//! \~english Restore operator, see \ref PIByteArray_sec1 for details
//! \~russian Оператор извлечения, подробнее в \ref PIByteArray_sec1
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);
//! \relatesalso PIByteArray @brief Restore operator, see \ref PIByteArray_sec1 for details
//! \relatesalso PIByteArray
//! \~english Restore operator, see \ref PIByteArray_sec1 for details
//! \~russian Оператор извлечения, подробнее в \ref PIByteArray_sec1
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {
if (s.size_s() < v.s) {
printf("error with RawData %d < %d\n", (int)s.size_s(), v.s);
@@ -378,13 +416,15 @@ inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {
return s;
}
//! \relatesalso PIByteArray @brief Restore operator for PIVector of any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector of any trivial copyable type
//! \~russian Оператор извлечения для PIVector тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", _TYPENAME_(T));
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -400,7 +440,7 @@ template<typename T,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", _TYPENAME_(T));
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -409,13 +449,15 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Restore operator for PIDeque of any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Restore operator for PIDeque of any trivial copyable type
//! \~russian Оператор извлечения для PIDeque тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -431,7 +473,7 @@ template<typename T,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -440,13 +482,15 @@ inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Restore operator for PIVector2D of any trivial copyable type
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector2D of any trivial copyable type
//! \~russian Оператор извлечения для PIVector2D тривиальных типов
template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r, c; s >> r >> c;
@@ -463,7 +507,7 @@ template<typename T,
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r,c;
@@ -473,10 +517,14 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Restore operator
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, PIBitArray & v) {assert(s.size_s() >= 8); s >> v.size_ >> v.data_; return s;}
//! \relatesalso PIPair @brief Restore operator
//! \relatesalso PIPair
//! \~english Restore operator
//! \~russian Оператор извлечения
template<typename Type0, typename Type1>
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
@@ -486,7 +534,9 @@ inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >
// store operators for complex types
//! \relatesalso PIByteArray @brief Store operator for PIVector of any compound type
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector of any compound type
//! \~russian Оператор сохранения для PIVector сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
s << int(v.size_s());
@@ -494,7 +544,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Store operator for PIDeque of any compound type
//! \relatesalso PIByteArray
//! \~english Store operator for PIDeque of any compound type
//! \~russian Оператор сохранения для PIDeque сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
s << int(v.size_s());
@@ -502,7 +554,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Store operator for PIVector2D of any compound type
//! \relatesalso PIByteArray
//! \~english Store operator for PIVector2D of any compound type
//! \~russian Оператор сохранения для PIVector2D сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
@@ -515,11 +569,13 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
// restore operators for complex types
//! \relatesalso PIByteArray @brief Restore operator for PIVector of any compound type
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector of any compound type
//! \~russian Оператор извлечения для PIVector сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) {
printf("error with PIVector<%s>\n", _TYPENAME_(T));
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -528,11 +584,13 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Restore operator for PIDeque of any compound type
//! \relatesalso PIByteArray
//! \~english Restore operator for PIDeque of any compound type
//! \~russian Оператор извлечения для PIDeque сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) {
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz;
@@ -541,11 +599,13 @@ inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
return s;
}
//! \relatesalso PIByteArray @brief Restore operator for PIVector2D of any compound type
//! \relatesalso PIByteArray
//! \~english Restore operator for PIVector2D of any compound type
//! \~russian Оператор извлечения для PIVector2D сложных типов
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) {
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
assert(s.size_s() >= 8);
}
int r,c;
@@ -561,6 +621,9 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
// other types
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
template <typename Key, typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
s << int(v.pim_index.size_s());
@@ -571,10 +634,13 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
}
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
template <typename Key, typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
if (s.size_s() < 4) {
printf("error with PIMap<%s, %s>\n", _TYPENAME_(Key), _TYPENAME_(T));
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
assert(s.size_s() >= 4);
}
int sz; s >> sz; v.pim_index.resize(sz);
@@ -606,16 +672,29 @@ inline PIByteArray & operator >>(PIByteArray & s, T & ) {
}
//! \relatesalso PIByteArray
//! \~english Returns PIByteArray::hash() of "ba"
//! \~russian Возвращает PIByteArray::hash() от "ba"
template<> inline uint piHash(const PIByteArray & ba) {return ba.hash();}
//! \relatesalso PIByteArray
//! \~english Swap contents betwee "f" and "s"
//! \~russian Меняет содержимое массивов "f" и "s"
template<> inline void piSwap(PIByteArray & f, PIByteArray & s) {f.swap(s);}
//! \relatesalso PIByteArray
//! \~english Store "value" to bytearray and returns it
//! \~russian Сохраняет "value" в байтовый массив и возвращает его
template <typename T> PIByteArray piSerialize(const T & value) {
PIByteArray ret;
ret << value;
return ret;
}
//! \relatesalso PIByteArray
//! \~english Restore type "T" from bytearray "data" and returns it
//! \~russian Извлекает тип "T" из байтового массива "data" и возвращает его
template <typename T> T piDeserialize(const PIByteArray & data) {
T ret;
if (!data.isEmpty()) {
@@ -626,7 +705,4 @@ template <typename T> T piDeserialize(const PIByteArray & data) {
}
#undef _TYPENAME_
#endif // PIBYTEARRAY_H

View File

@@ -1,6 +1,3 @@
/*! @file pichar.h
* @brief Unicode char
*/
/*
PIP - Platform Independent Primitives
Unicode char
@@ -21,7 +18,7 @@
*/
#include "piincludes_p.h"
#include "pibytearray.h"
#include "pistring.h"
#ifdef PIP_ICU
# define U_NOEXCEPT
# include "unicode/ucnv.h"
@@ -38,18 +35,25 @@ char * __utf8name__ = 0;
# include <ctype.h>
#endif
#include <wchar.h>
#ifdef ANDROID
# if __ANDROID_API__ < 21
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
# endif
#endif
/*! \class PIChar
* @brief Unicode char
* \details This class is wrapper around \c "uint".
* There are many contructors and information functions
*/
//! \addtogroup Core
//! \{
//! \class PIChar pichar.h
//!
//! \~\brief
//! \~english %PIChar represents a single character
//! \~russian %PIChar представляет собой один символ строки
//!
//! \~\details
//! \~english
//! This class is wrapper around UTF16.
//! There are many contructors and information functions
//!
//! \~russian
//! %PIChar хранит один сивол в UTF16. Имеет много контрукторов, геттеров в различные
//! кодировки (системную, консольную, UTF8) и информационных функций.
//!
//! \}
ushort charFromCodepage(const char * c, int size, const char * codepage, int * taken = 0) {
@@ -76,12 +80,14 @@ ushort charFromCodepage(const char * c, int size, const char * codepage, int * t
if (taken) *taken = ret;
return buffer;
# else
wchar_t wc(0);
mbtowc(0, 0, 0); // reset mbtowc
ret = mbtowc(&wc, c, size);
mbstate_t state;
memset(&state, 0, sizeof(state));
wchar_t wc;
ret = mbrtowc(&wc, c, size, &state);
//printf("mbtowc = %d\n", ret);
//piCout << errorString();
if (ret < 1) return 0;
return ushort(int(wc));
return ushort(wc);
# endif
#endif
return ushort(c[0]);
@@ -324,12 +330,12 @@ char PIChar::toSystem() const {
PIChar PIChar::toUpper() const {
if (isAscii()) return PIChar(toupper(ch));
if (isAscii()) return PIChar((ushort)toupper(ch));
#ifdef PIP_ICU
UChar c(0);
UErrorCode e((UErrorCode)0);
u_strToUpper(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c);
return PIChar((ushort)c);
#else
# ifdef WINDOWS
ushort wc = 0;
@@ -337,17 +343,17 @@ PIChar PIChar::toUpper() const {
return PIChar(wc);
# endif
#endif
return PIChar(towupper(ch));
return PIChar((ushort)towupper(ch));
}
PIChar PIChar::toLower() const {
if (isAscii()) return PIChar(tolower(ch));
if (isAscii()) return PIChar((ushort)tolower(ch));
#ifdef PIP_ICU
UChar c(0);
UErrorCode e((UErrorCode)0);
u_strToLower(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c);
return PIChar((ushort)c);
#else
# ifdef WINDOWS
ushort wc = 0;
@@ -355,7 +361,7 @@ PIChar PIChar::toLower() const {
return PIChar(wc);
# endif
#endif
return PIChar(towlower(ch));
return PIChar((ushort)towlower(ch));
}
@@ -377,15 +383,9 @@ PICout operator <<(PICout s, const PIChar & v) {
} else
#endif
#ifdef WINDOWS
s << v.toSystem();
s << v.toSystem();
#else
{
char tc[8];
wctomb(0, 0);
int sz = wctomb(tc, v.ch);
for (int b = 0; b < sz; ++b)
s << tc[b];
}
s << PIString(v);
#endif
}
s.restoreControl();

View File

@@ -1,5 +1,8 @@
/*! @file pichar.h
* @brief Unicode char
/*! \file pichar.h
* \ingroup Core
* \~\brief
* \~english Single string character
* \~russian Один символ строки
*/
/*
PIP - Platform Independent Primitives
@@ -34,97 +37,138 @@ class PIP_EXPORT PIChar
friend class PIString;
friend PICout PIP_EXPORT operator <<(PICout s, const PIChar & v);
public:
//! Contructs ascii symbol
PIChar(const char c) {ch = c; ch &= 0xFF;}
//! \~english Contructs Ascii symbol
//! \~russian Создает символ Ascii
PIChar(char c) {ch = c; ch &= 0xFF;}
//! Contructs 2-bytes symbol
PIChar(const short c) {ch = c;}
//! \~english Contructs ascii symbol
//! \~russian Создает символ Ascii
PIChar(uchar c) {ch = c;}
//! Contructs 4-bytes symbol
PIChar(const int c) {ch = c;}
//! \~english Contructs 2-bytes symbol
//! \~russian Создает 2-байтный символ
PIChar(ushort c = 0) {ch = c;}
//! Contructs ascii symbol
PIChar(const uchar c) {ch = c; ch &= 0xFF;}
//! \~english Contructs 2-bytes symbol from `wchar_t`
//! \~russian Создает 2-байтный символ из `wchar_t`
PIChar(wchar_t c) {ch = c;}
//! Contructs 2-bytes symbol
PIChar(const ushort c) {ch = c;}
//! Default constructor. Contructs 4-bytes symbol
PIChar(const uint c = 0) {ch = c;}
//! Contructs symbol from no more than 4 bytes of string
//! \~english Contructs symbol from system locale and no more than 4 bytes of string
//! \~russian Создает символ из системной локали не более 4 байт длины
PIChar(const char * c, int * bytes = 0);
//! Copy operator
//! \~english Copy operator
//! \~russian Оператор присваивания
PIChar & operator =(const char v) {ch = v; return *this;}
//! Compare operator
//! \~english Copy operator
//! \~russian Оператор присваивания
PIChar & operator =(const wchar_t v) {ch = v; return *this;}
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const PIChar & o) const;
//! Compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const PIChar & o) const {return !(o == *this);}
//! Compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const PIChar & o) const;
//! Compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const PIChar & o) const;
//! Compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const PIChar & o) const;
//! Compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const PIChar & o) const;
//! Return \b true if symbol is digit ('0' to '9')
//! \~english Returns \b true if symbol is digit ('0' to '9')
//! \~russian Возвращает \b true если символ является
bool isDigit() const;
//! Return \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F')
//! \~english Returns \b true if symbol is HEX digit ('0' to '9', 'a' to 'f', 'A' to 'F')
//! \~russian Возвращает \b true если символ является HEX цифрой ('0' до '9', 'a' до 'f', 'A' до 'F')
bool isHex() const;
//! Return \b true if symbol is drawable (without space)
//! \~english Returns \b true if symbol is drawable (without space)
//! \~russian Возвращает \b true если символ является графическим (исключая пробельные)
bool isGraphical() const;
//! Return \b true if symbol is control byte (< 32 or 127)
//! \~english Returns \b true if symbol is control byte (< 32 or 127)
//! \~russian Возвращает \b true если символ является контрольным (< 32 or 127)
bool isControl() const;
//! Return \b true if symbol is in lower case
//! \~english Returns \b true if symbol is in lower case
//! \~russian Возвращает \b true если символ в нижнем регистре
bool isLower() const;
//! Return \b true if symbol is in upper case
//! \~english Returns \b true if symbol is in upper case
//! \~russian Возвращает \b true если символ в верхнем регистре
bool isUpper() const;
//! Return \b true if symbol is printable (with space)
//! \~english Returns \b true if symbol is printable (with space)
//! \~russian Возвращает \b true если символ является печатным (включая пробельные)
bool isPrint() const;
//! Return \b true if symbol is space or tab
//! \~english Returns \b true if symbol is space or tab
//! \~russian Возвращает \b true если символ является пробельным или табуляцией
bool isSpace() const;
//! Return \b true if symbol is alphabetical letter
//! \~english Returns \b true if symbol is alphabetical letter
//! \~russian Возвращает \b true если символ является алфавитной буквой
bool isAlpha() const;
//! Return \b true if symbol is ascii (< 128)
//! \~english Returns \b true if symbol is Ascii (< 128)
//! \~russian Возвращает \b true если символ является Ascii (< 128)
bool isAscii() const;
const wchar_t * toWCharPtr() const;
//! Return as <tt>"char * "</tt> string
//! \~english Returns as `char *` string
//! \~russian Возвращает символ как указатель на `char *`
const char * toCharPtr() const;
wchar_t toWChar() const;
//! \~english Returns symbol as Ascii
//! \~russian Возвращает символ в Ascii
char toAscii() const {return ch % 256;}
//! \~english Returns symbol as console codepage
//! \~russian Возвращает символ в консольной кодировке
char toConsole1Byte() const;
//! \~english Returns symbol as system codepage
//! \~russian Возвращает символ в системной кодировке
char toSystem() const;
ushort unicode16Code() const {return ch;}
//! Return symbol in upper case
//! \~english Returns symbol in upper case
//! \~russian Возвращает символ в нижнем регистре
PIChar toUpper() const;
//! Return symbol in lower case
//! \~english Returns symbol in lower case
//! \~russian Возвращает символ в верхнем регистре
PIChar toLower() const;
//! \~english Returns symbol from console codepage
//! \~russian Возвращает символ из консольной кодировки
static PIChar fromConsole(char c);
//! \~english Returns symbol from system codepage
//! \~russian Возвращает символ из системной кодировки
static PIChar fromSystem(char c);
//! \~english Returns symbol from UTF8 codepage
//! \~russian Возвращает символ из UTF8 кодировки
static PIChar fromUTF8(const char * c);
private:
@@ -132,54 +176,86 @@ private:
};
//! Output operator to \a PICout
//! \relatesalso PIChar
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
PICout PIP_EXPORT operator <<(PICout s, const PIChar & v);
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator ==(const char v, const PIChar & c) {return (PIChar(v) == c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >(const char v, const PIChar & c) {return (PIChar(v) > c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <(const char v, const PIChar & c) {return (PIChar(v) < c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const char v, const PIChar & c) {return (PIChar(v) >= c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const char v, const PIChar & c) {return (PIChar(v) <= c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator ==(const char * v, const PIChar & c) {return (PIChar(v) == c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >(const char * v, const PIChar & c) {return (PIChar(v) > c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <(const char * v, const PIChar & c) {return (PIChar(v) < c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const char * v, const PIChar & c) {return (PIChar(v) >= c);}
//! Compare operator
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const char * v, const PIChar & c) {return (PIChar(v) <= c);}
//! Compare operator
inline bool operator ==(const int v, const PIChar & c) {return (PIChar(v) == c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator ==(const int v, const PIChar & c) {return (PIChar((ushort)v) == c);}
//! Compare operator
inline bool operator >(const int v, const PIChar & c) {return (PIChar(v) > c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >(const int v, const PIChar & c) {return (PIChar((ushort)v) > c);}
//! Compare operator
inline bool operator <(const int v, const PIChar & c) {return (PIChar(v) < c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <(const int v, const PIChar & c) {return (PIChar((ushort)v) < c);}
//! Compare operator
inline bool operator >=(const int v, const PIChar & c) {return (PIChar(v) >= c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const int v, const PIChar & c) {return (PIChar((ushort)v) >= c);}
//! Compare operator
inline bool operator <=(const int v, const PIChar & c) {return (PIChar(v) <= c);}
//! \relatesalso PIChar
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const int v, const PIChar & c) {return (PIChar((ushort)v) <= c);}
#endif // PICHAR_H

View File

@@ -19,45 +19,77 @@
#include "pichunkstream.h"
/*! \class PIChunkStream
* @brief Class for binary serialization
*
* \section PIChunkStream_sec0 Synopsis
* This class provides very handly mechanism to store and restore values to and from
* \a PIByteArray. The main advantage of using this class is that your binary data
* become independent from order and collection of your values.
*
* \section PIChunkStream_sec1 Mechanism
* %PIChunkStream works with items called "chunk". Chunk is an ID and any value that
* can be stored and restored to \a PIByteArray with stream operators << and >>.
* You can place chunks to stream and read chunks from stream.
*
* To construct %PIChunkStream for writing data use any constructor. Empty constructor
* creates internal empty buffer that can be accessed by function \a data().
* Non-empty constructor works with given byte array.
*
* To read chunks from byte array use function \a read() that returns ID of
* next chunk. Then you can get value of this chunk with function \a getData(),
* but you should definitely know type of this value. You can read from byte array
* while \a atEnd() if false.
*
* \section PIChunkStream_sec2 Examples
*
* Using simple operator and cascade serialization:
*
* Prepare your structs to work with %PIChunkStream:
* \snippet pichunkstream.cpp struct
* Old-style writing to %PIChunkStream:
* \snippet pichunkstream.cpp write
* Fastest reading from %PIChunkStream:
* \snippet pichunkstream.cpp read
*
* And next code show how to serialize your struct with %PIChunkStream:
* \snippet pichunkstream.cpp write_new
*
* ... and deserialize:
* \snippet pichunkstream.cpp read_new
*/
//! \addtogroup Core
//! \{
//! \class PIChunkStream pichunkstream.h
//! \brief
//! \~english Class for binary de/serialization
//! \~russian Класс для бинарной де/сериализации
//!
//! \~english \section PIChunkStream_sec0 Synopsis
//! \~russian \section PIChunkStream_sec0 Краткий обзор
//! \~english
//! This class provides very handly mechanism to store and restore values to and from
//! \a PIByteArray. The main advantage of using this class is that your binary data
//! become independent from order and collection of your values.
//!
//! \~russian
//! Этот класс предоставляет очень удобный механизм для сохранения и извлечения значений
//! в/из \a PIByteArray. Главным плюсом является то, что данные не будут зависеть от порядка
//! и наличия значений.
//!
//! \~english \section PIChunkStream_sec1 Mechanism
//! \~russian \section PIChunkStream_sec1 Механизм
//! \~english
//! %PIChunkStream works with items called "chunk". Chunk is an ID, size and any value that
//! can be stored and restored to/from %PIChunkStream with stream operators << and >>.
//!
//! To construct %PIChunkStream for writing data use any non-default constructor. Empty constructor
//! creates internal buffer that can be accessed by function \a data().
//! Non-empty constructor works with given byte array.
//!
//! To read chunks from byte array use function \a read() that returns ID of
//! readed chunk. Then you can get value of this chunk with functions \a getData() or \a get(),
//! but you should definitely know type of this value. You can read from byte array
//! while \a atEnd() if false.
//!
//! \~russian
//! %PIChunkStream работает с элементами под названием "чанк". Чанк имеет ID, размер и значение,
//! и может быть записан или прочитан в/из %PIChunkStream с помощью операторов << и >>.
//!
//! Для создания потока на запись используется любой не-умолчальный конструктор. Пустой конструктор
//! создает внутренний буфер, который можно получить с помощью метода \a data().
//! Непустой конструктор работает с переданным байтовым массивом.
//!
//! Для чтения чанков из байтового массива используется метод \a read(), который возвращает
//! ID прочитанного чанка. Получить значение этого чанка далее можно с помощью методов \a getData() или get(),
//! но тип значения должен быть известен. Читать из потока можно пока метод \a atEnd() возвращает ложь.
//!
//! \~english \section PIChunkStream_sec2 Examples
//! \~russian \section PIChunkStream_sec2 Пример
//!
//! \~english Using simple operator and cascade serialization:
//! \~russian Использование простого оператора и каскадная сериализация:
//!
//! \~english Prepare your structs to work with %PIChunkStream:
//! \~russian Подготовка своей структуры для работы с %PIChunkStream:
//! \~\snippet pichunkstream.cpp struct
//! \~english Old-style writing to %PIChunkStream:
//! \~russian Старый стиль использования %PIChunkStream:
//! \~\snippet pichunkstream.cpp write
//! \~english Fastest reading from %PIChunkStream:
//! \~russian Самое быстрое чтение из %PIChunkStream:
//! \~\snippet pichunkstream.cpp read
//!
//! \~english And next code show how to serialize your struct with %PIChunkStream:
//! \~russian Следующий код показывает, как сериализовать свою структуру в %PIChunkStream:
//! \~\snippet pichunkstream.cpp write_new
//!
//! \~english ... and deserialize:
//! \~russian ... и десериализовать:
//! \~\snippet pichunkstream.cpp read_new
//!
//! \}
void PIChunkStream::setSource(const PIByteArray & data) {

View File

@@ -1,5 +1,8 @@
/*! @file pichunkstream.h
* @brief Binary markup serializator
/*! \file pichunkstream.h
* \ingroup Core
* \~\brief
* \~english Binary markup de/serializator stream
* \~russian Бинарный поток для де/сериализации с разметкой
*/
/*
PIP - Platform Independent Primitives
@@ -30,20 +33,27 @@ class PIP_EXPORT PIChunkStream
{
public:
//! \~english
//! Version of data packing. Read-access %PIChunkStream automatic detect version, but write-access
//! %PIChunkStream by default write in new version, be careful!
//! \~russian
//! Версия хранения данных. %PIChunkStream на чтение автоматически определяет версию, но для записи
//! использует по умолчанию новую, осторожно!
enum Version {
Version_1 /*! First, old version */,
Version_2 /*! Second, more optimized version */ = 2,
Version_1 /*! \~english First, old version \~russian Первая, старая версия */,
Version_2 /*! \~english Second, more optimized version \~russian Вторая, более оптимизированная версия */ = 2,
};
//! Contructs stream for read from "data"
//! \~english Contructs stream for read from "data"
//! \~russian Создает поток на чтение из "data"
PIChunkStream(const PIByteArray & data): version_(Version_2) {setSource(data);}
//! Contructs stream for read or write to/from "data", or empty stream for write
//! \~english Contructs stream for read or write to/from "data", or empty stream for write if "data" = 0
//! \~russian Создает поток на чтение или запись из/в "data", или пустой поток на запись если "data" = 0
PIChunkStream(PIByteArray * data = 0, Version v = Version_2): version_(v) {setSource(data);}
//! Contructs empty stream for write with version \"v\"
//! \~english Contructs empty stream for write with version \"v\"
//! \~russian Создает пустой поток на запись с версией \"v\"
PIChunkStream(Version v): version_(v) {setSource(0);}
~PIChunkStream();
@@ -61,48 +71,64 @@ public:
const T & data;
};
//! Returns chunk with ID "id" and value "data" for write to stream
//! \~english Returns chunk with ID "id" and value "data" for write to stream
//! \~russian Возвращает чанк с ID "id" и значением "data" для записи в поток
template <typename T> static ChunkConst<T> chunk(int id, const T & data) {return ChunkConst<T>(id, data);}
//! Add data to this chunk strean with ID "id" and value "data"
//! \~english Add to this stream chunk with ID "id" and value "data"
//! \~russian Добавляет в этот поток чанк с ID "id" и значением "data"
template <typename T> PIChunkStream & add(int id, const T & data) {*this << ChunkConst<T>(id, data); return *this;}
//! \~english
//! Extract %PIByteArray from "data" and set it current stream.
//! If "read_all" then call \a readAll() after extract.
//! Returns if has data to read.
//! \~russian
//! Извлекает %PIByteArray из "data" и инициализирует им поток.
//! Если указан "read_all", то вызывает \a readAll() после инициализации.
//! Возвращает если ли данные для чтения.
bool extract(PIByteArray & data, bool read_all = false);
void setSource(const PIByteArray & data);
void setSource(PIByteArray * data);
//! Returns internal buffer with written data
//! \~english Returns internal buffer with written data
//! \~russian Возвращает внутренний буфер с записанными данными
PIByteArray data() const;
//! Returns if there is end of stream
//! \~english Returns if there is end of stream
//! \~russian Возвращает достигнут ли конец потока
bool atEnd() const {return data_->size_s() <= 1;}
//! Returns stream version
//! \~english Returns stream version
//! \~russian Возвращает версию потока
Version version() const {return (Version)version_;}
//! Read one chunk from stream and returns its ID
//! \~english Read one chunk from stream and returns its ID
//! \~russian Читает один чанк из потока и возвращает его ID
int read();
//! Read all chunks from stream. This function just index input data
//! \~english Read all chunks from stream. This function just index input data
//! \~russian Читает все чанки из потока. Данный метод лишь индексирует данные
void readAll();
//! Returns last readed chunk ID
//! \~english Returns last readed chunk ID
//! \~russian Возвращает ID последнего прочитанного чанка
int getID() {return last_id;}
//! Returns value of last readed chunk
//! \~english Returns value of last readed chunk
//! \~russian Возвращает значение последнего прочитанного чанка
template <typename T>
T getData() const {T ret; PIByteArray s(last_data); s >> ret; return ret;}
//! Place value of last readed chunk into \"v\"
//! \~english Place value of last readed chunk into \"v\"
//! \~russian Записывает значение последнего прочитанного чанка в \"v\"
template <typename T>
void get(T & v) const {v = getData<T>();}
//! Place value of chunk with id \"id\" into \"v\". You should call \a readAll() before using this function!
//! \~english Place value of chunk with ID \"id\" into \"v\". You should call \a readAll() before using this function!
//! \~russian Записывает значение чанка с ID \"id\" в \"v\". Необходимо вызвать \a readAll() перед использованием этого метода!
template <typename T>
const PIChunkStream & get(int id, T & v) const {
CacheEntry pos = data_map.value(id);
@@ -113,7 +139,8 @@ public:
return *this;
}
//! Replace value of chunk with ID \"id\" to \"v\". You should call \a readAll() before using this function!
//! \~english Replace value of chunk with ID \"id\" to \"v\". You should call \a readAll() before using this function!
//! \~russian Заменяет значение чанка с ID \"id\" на \"v\". Необходимо вызвать \a readAll() перед использованием этого метода!
template <typename T>
PIChunkStream & set(int id, const T & v) {
PIByteArray ba;

View File

@@ -21,16 +21,52 @@
#include "pisysteminfo.h"
/*! \class PICLI
* @brief Command-line arguments parser
*
* \section PICLI_sec0 Synopsis
* This class provide handy parsing of command-line arguments. First you should add
* arguments to PICLI with function \a addArgument(). Then you can check if there
* is some argument in application command-line with function \a hasArgument();
* \section PICLI_sec1 Example
* \snippet picli.cpp main
*/
//! \addtogroup Core
//! \{
//! \class PICLI picli.h
//! \~\brief
//! \~english Command-Line parser
//! \~russian Парсер командной строки
//!
//! \~english \section PICLI_sec0 Synopsis
//! \~russian \section PICLI_sec0 Краткий обзор
//! \~english
//! This class provide handy parsing of command-line arguments. First you should add
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
//! is some argument in application command-line with function \a hasArgument(),
//! or obtain argument value by \a argumentValue().
//!
//! \~russian
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
//! а также получить их значения при помощи \a argumentValue().
//!
//! \~english \section PICLI_sec1 Example
//! \~russian \section PICLI_sec0 Пример
//! \~\code
//! int main(int argc, char ** argv) {
//! PICLI cli(argc, argv);
//! cli.addArgument("console");
//! cli.addArgument("debug");
//! cli.addArgument("Value", "v", "value", true);
//! if (cli.hasArgument("console"))
//! piCout << "console active";
//! if (cli.hasArgument("debug"))
//! piCout << "debug active";
//! piCout << "Value =" << cli.argumentValue("Value");
//! return 0;
//! }
//!
//! These executions are similar:
//! a.out -cd -v 10
//! a.out --value 10 -dc
//! a.out -c -v 10 -d
//! a.out --console -d -v 10
//! a.out --debug -c --value 10
//! \endcode
//!
//! \}
PICLI::PICLI(int argc, char * argv[]) {

View File

@@ -1,5 +1,8 @@
/*! @file picli.h
* @brief Command-Line parser
/*! \file picli.h
* \ingroup Core
* \~\brief
* \~english Command-Line parser
* \~russian Парсер командной строки
*/
/*
PIP - Platform Independent Primitives
@@ -30,39 +33,54 @@ class PIP_EXPORT PICLI: public PIObject
PIOBJECT_SUBCLASS(PICLI, PIObject)
public:
//! Constructor
//! \~english Constructor
//! \~russian Конструктор
PICLI(int argc, char * argv[]);
//! Add argument with name "name", short key = name first letter, full key = name
//! \~english Add argument with name "name", short key = name first letter and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = первой букве имени и полным ключом = имени
void addArgument(const PIString & name, bool value = false) {_args << Argument(name, name[0], name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = name
//! \~english Add argument with name "name", short key = "shortKey" and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени
void addArgument(const PIString & name, const PIChar & shortKey, bool value = false) {_args << Argument(name, shortKey, name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = name
//! \~english Add argument with name "name", short key = "shortKey" and full key = name
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = имени
void addArgument(const PIString & name, const char * shortKey, bool value = false) {_args << Argument(name, PIChar(shortKey), name, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey"
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey"
void addArgument(const PIString & name, const PIChar & shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, shortKey, fullKey, value); needParse = true;}
//! Add argument with name "name", short key = "shortKey", full key = "fullKey"
//! \~english Add argument with name "name", short key = "shortKey" and full key = "fullKey"
//! \~russian Добавляет аргумент с именем "name", коротким ключом = "shortKey" и полным ключом = "fullKey"
void addArgument(const PIString & name, const char * shortKey, const PIString & fullKey, bool value = false) {_args << Argument(name, PIChar(shortKey), fullKey, value); needParse = true;}
//! Returns unparsed command-line argument by index "index". Index 0 is program execute command.
//! \~english Returns unparsed command-line argument by index "index". Index 0 is program execute command
//! \~russian Возвращает исходный аргумент командной строки по индексу "index". Индекс 0 это команда вызова программы
PIString rawArgument(int index) {parse(); return _args_raw[index];}
PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
PIString optionalArgument(int index) {parse(); return _args_opt[index];}
//! Returns unparsed command-line arguments
//! \~english Returns unparsed command-line arguments
//! \~russian Возвращает исходные аргументы командной строки
const PIStringList & rawArguments() {parse(); return _args_raw;}
const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
const PIStringList & optionalArguments() {parse(); return _args_opt;}
//! Returns program execute command without arguments
//! \~english Returns program execute command without arguments
//! \~russian Возвращает команду вызова программы без аргументов
PIString programCommand() {parse(); return _args_raw.size() > 0 ? _args_raw.front() : PIString();}
//! \~english Returns if argument "name" found
//! \~russian Возвращает найден ли аргумент "name"
bool hasArgument(const PIString & name) {parse(); piForeach (Argument & i, _args) if (i.name == name && i.found) return true; return false;}
//! \~english Returns argument "name" value, or empty string if this is no value
//! \~russian Возвращает значение аргумента "name" или пустую строку, если значения нет
PIString argumentValue(const PIString & name) {parse(); piForeach (Argument &i, _args) if (i.name == name && i.found) return i.value; return PIString();}
PIString argumentShortKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.short_key; return PIString();}
PIString argumentFullKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.full_key; return PIString();}

View File

@@ -20,15 +20,28 @@
#include "picollection.h"
/** \class PICollection
* @brief Interface to discover element groups
* \details
* \section PICollection_sec0 Synopsis
* This class has only static functions so no need to create instance of the
* %PICollection. This class provide macros to add some classes or existing
* objects to global collection and access to them from any place of the code.
* \snippet picollection.cpp main
* */
//! \addtogroup Core
//! \{
//! \~\class PICollection picollection.h
//! \~\brief
//! \~english Helper to collect and retrieve classes to groups
//! \~russian Помощник для создания и получения классов в группы
//!
//! \~\details
//! \~english \section PICollection_sec0 Synopsis
//! \~russian \section PICollection_sec0 Краткий обзор
//! \~english
//! This class has only static functions so no need to create instance of the
//! %PICollection. This class provide macros to add some classes or existing
//! objects to global collection and access to them from any place of the code.
//!
//! \~russian
//! Этот класс предоставляет статические методы, поэтому не нужно создавать
//! его экземпляр. Имеется несколько макросов для добавления классов или существующих
//! объектов в глобальные группы. Затем можно получить их список в любом месте программы.
//! \~\snippet picollection.cpp main
//!
//! \}
PIStringList PICollection::groups() {
@@ -77,7 +90,8 @@ PIVector<PICollection::Group> & PICollection::_groups() {
PICollection::CollectionAdder::CollectionAdder(const PIString & group, const PIObject * element, const PIString & name, bool own) {
if (!element) return;
const_cast<PIObject * >(element)->setName(name);
if (name.isNotEmpty())
const_cast<PIObject * >(element)->setName(name);
bool added = PICollection::addToGroup(group, element);
if (!added && own)
delete element;

View File

@@ -1,5 +1,8 @@
/*! @file picollection.h
* @brief Custom elements collection
/*! \file picollection.h
* \ingroup Core
* \~\brief
* \~english Unique classes collection
* \~russian Коллекция уникальных классов
*/
/*
PIP - Platform Independent Primitives
@@ -27,32 +30,70 @@
#ifdef DOXYGEN
/** @brief Add existing element "object" in group with name "group"
* \relatesalso PICollection
* \details If there is no group with name "group" it will be created.
* Only one element of the class "object" can be in group "group". If
* this is already exists nothing be happens. \n "object" should to
* be pointer to object based on PIObject. */
//! \~\relatesalso PICollection
//! \~\brief
//! \~english Add existing element "object" in group with name "group"
//! \~russian Добавляет существующий элемент "object" в группу с именем "group"
//! \~\details
//! \~english
//! If this is no group with name "group" it will be created.
//! Only one element of the class "object" can be in group. If
//! this is already exists nothing be happens. \n "object" should to
//! be pointer to object based on \a PIObject.
//! \~russian
//! Если такой группы нет, она создается. В каждой группе может присутствовать
//! только один элемент класса объекта "object". Если такой элемент уже есть,
//! то ничего не изменится. \n "object" должен быть наследником \a PIObject.
# define ADD_TO_COLLECTION(group, object)
/** @brief Add new element of class "class" in group with name "group"
* \relatesalso PICollection
* \details If there is no group with name "group" it will be created.
* Only one element of the class "class" can be in group "group". If
* this is already exists nothing be happens. \n "class" should to
* be name of the any class based on PIObject. */
//! \~\relatesalso PICollection
//! \~\brief
//! \~english Add existing element "object" in group with name "group" and set its name to "name"
//! \~russian Добавляет существующий элемент "object" в группу с именем "group" и присваивает объекту имя "name"
//! \~\details
//! \~english
//! Similar to \a ADD_TO_COLLECTION(group, object) but set object name to "name"
//! \~russian
//! Аналогично \a ADD_TO_COLLECTION(group, object), но присваивает имя объекту "name"
# define ADD_TO_COLLECTION_WITH_NAME(group, object, name)
//! \~\relatesalso PICollection
//! \~\brief
//! \~english Add new element of class "class" in group with name "group"
//! \~russian Добавляет новый элемент класса "class" в группу с именем "group"
//! \~\details
//! \~english
//! If this is no group with name "group" it will be created.
//! Only one element of the class "class" can be in group. If
//! this is already exists nothing be happens. \n "class" should to
//! be name of the any class based on PIObject.
//! \~russian
//! Если такой группы нет, она создается. В каждой группе может присутствовать
//! только один элемент класса "class". Если такой элемент уже есть,
//! то ничего не изменится. \n "class" должен быть любым классом, наследным от \a PIObject.
# define ADD_NEW_TO_COLLECTION(group, class)
//! \~\relatesalso PICollection
//! \~\brief
//! \~english Add new element of class "class" in group with name "group" and set its name to "name"
//! \~russian Добавляет новый элемент класса "class" в группу с именем "group" и присваивает объекту имя "name"
//! \~\details
//! \~english
//! Similar to \a ADD_NEW_TO_COLLECTION(group, class) but set object name to "name"
//! \~russian
//! Аналогично \a ADD_NEW_TO_COLLECTION(group, class), но присваивает имя объекту "name"
# define ADD_NEW_TO_COLLECTION_WITH_NAME(group, class, name)
#else
# define ADD_TO_COLLECTION(group, object) \
static PICollection::CollectionAdder _PIP_ADD_COUNTER(_collection_adder_)(#group, object, false);
static PICollection::CollectionAdder _PIP_ADD_COUNTER(_collection_adder_)(#group, object, "", false);
# define ADD_TO_COLLECTION_WITH_NAME(group, object, name) \
static PICollection::CollectionAdder _PIP_ADD_COUNTER(_collection_adder_)(#group, object, #name, false);
# define ADD_NEW_TO_COLLECTION(group, class) \
static PICollection::CollectionAdder _PIP_ADD_COUNTER(_collection_adder_)(#group, new class(), true);
static PICollection::CollectionAdder _PIP_ADD_COUNTER(_collection_adder_)(#group, new class(), "", true);
# define ADD_NEW_TO_COLLECTION_WITH_NAME(group, class, name) \
static PICollection::CollectionAdder _PIP_ADD_COUNTER(_collection_adder_)(#group, new class(), #name, true);
@@ -65,10 +106,12 @@ class PIP_EXPORT PICollection
public:
PICollection() {;}
//! @brief Returns all existing groups by their names
//! \~english Returns all existing groups by their names
//! \~russian Возвращает имена всех групп
static PIStringList groups();
//! @brief Returns all elements of group "group"
//! \~english Returns all elements of group "group"
//! \~russian Возвращает все элементы группы "group"
static PIVector<const PIObject * > groupElements(const PIString & group);
static bool addToGroup(const PIString & group, const PIObject * element);

View File

@@ -0,0 +1,158 @@
/*
PIP - Platform Independent Primitives
C-String class
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 "piconstchars.h"
#include "pistring.h"
//! \addtogroup Core
//! \{
//! \~\class PIConstChars piconstchars.h
//! \~\brief
//! \~english C-String class
//! \~russian Класс C-строки
//!
//! \~english \section PICout_sec0 Synopsis
//! \~russian \section PICout_sec0 Краткий обзор
//! \~english
//! This is wrapper around \c const char * string. %PIConstChars doesn`t
//! copy string, just save pointer and size.
//!
//! Provides API similar to string, with information and compare methods.
//!
//! Used to more handly works with ordinary C-strings.
//!
//! \~russian
//! Это обертка вокруг \c const char * строки. %PIConstChars не скопирует
//! строку, а хранит только указатель и размер.
//!
//! Предоставляет API схожий с обычной строкой, с методами сравнения и информационными.
//!
//! Используется для более удобной работы с обычными C-строками.
//!
//! \}
bool PIConstChars::startsWith(const PIConstChars & str) const {
if (size() < str.size()) return false;
return str == left(str.size());
}
bool PIConstChars::endsWith(const PIConstChars & str) const {
if (size() < str.size()) return false;
return str == right(str.size());
}
PIConstChars PIConstChars::mid(const int start, const int len) const {
int s = start, l = len;
if (l == 0 || s >= (int)size() || isEmpty()) return PIConstChars("");
if (s < 0) {
l += s;
s = 0;
}
if (l < 0) {
return PIConstChars(str + s, (int)size() - s);
} else {
if (l > (int)size() - s)
l = (int)size() - s;
return PIConstChars(str + s, l);
}
return PIConstChars("");
}
PIConstChars PIConstChars::left(const int l) const {
if (l <= 0) return PIConstChars("");
return mid(0, l);
}
PIConstChars PIConstChars::right(const int l) const {
if (l <= 0) return PIConstChars("");
return mid((int)size() - l, l);
}
PIConstChars & PIConstChars::cutLeft(const int l) {
if (l <= 0) return *this;
if (l >= (int)size())
*this = PIConstChars("");
else {
str += l;
len -= l;
}
return *this;
}
PIConstChars & PIConstChars::cutRight(const int l) {
if (l <= 0) return *this;
if (l >= (int)size())
*this = PIConstChars("");
else {
len -= l;
}
return *this;
}
PIConstChars PIConstChars::takeLeft(const int len) {
PIConstChars ret(left(len));
cutLeft(len);
return ret;
}
PIConstChars PIConstChars::takeRight(const int len) {
PIConstChars ret(right(len));
cutRight(len);
return ret;
}
PIConstChars & PIConstChars::trim() {
if (isEmpty()) return *this;
int st = -1, fn = 0;
for (int i = 0; i < (int)len; ++i) {
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0)) {
st = i;
break;
}
}
if (st < 0) {
*this = PIConstChars("");
return *this;
}
for (int i = (int)len - 1; i >= 0; --i) {
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0)) {
fn = i;
break;
}
}
if (fn < (int)len - 1) cutRight((int)len - fn - 1);
if (st > 0) cutLeft(st);
return *this;
}
PIString PIConstChars::toString() const {
if (isEmpty()) return PIString();
return PIString::fromAscii(str, len);
}

View File

@@ -0,0 +1,250 @@
/*! \file piconstchars.h
* \ingroup Core
* \brief
* \~english C-String class
* \~russian Класс C-строки
*/
/*
PIP - Platform Independent Primitives
C-String class
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 PICONSTCHARS_H
#define PICONSTCHARS_H
#include "picout.h"
class PIP_EXPORT PIConstChars {
public:
//! \~english Contructs an null string.
//! \~russian Создает нулевую строку.
PIConstChars() {}
//! \~english Contructs string from C-string "string".
//! \~russian Создает строку из C-строки "string".
PIConstChars(const char * string) {
str = string;
len = strlen(string);
}
//! \~english Contructs string from "size" characters of buffer "data".
//! \~russian Создает строку из "size" символов массива "data".
PIConstChars(const char * data, size_t size) {
str = data;
len = size;
}
//! \~english Contructs a copy of string.
//! \~russian Создает копию строки.
PIConstChars(const PIConstChars & o) {
str = o.str;
len = o.len;
}
//! \~english Read-only access to character by `index`.
//! \~russian Доступ на чтение к символу по индексу `index`.
inline char operator [](size_t index) const {return str[index];}
//! \~english Read-only access to character by `index`.
//! \~russian Доступ на чтение к символу по индексу `index`.
inline char at(size_t index) const {return str[index];}
//! \~english Returns \c char * string pointer.
//! \~russian Возвращает \c char * указатель строки.
inline const char * data() const {return str;}
//! \~english Returns \c true if string doesn`t have any data.
//! \~russian Возвращает \c true если строка не имеет данных.
inline bool isNull() const {return !str;}
//! \~english Returns \c true if string is empty, i.e. length = 0, or null.
//! \~russian Возвращает \c true если строка пустая, т.е. длина = 0, или нулевая.
inline bool isEmpty() const {return len == 0;}
//! \~english Returns \c true if string is not empty, i.e. length > 0.
//! \~russian Возвращает \c true если строка непустая, т.е. длина > 0.
inline bool isNotEmpty() const {return len > 0;}
//! \~english Returns characters length of string.
//! \~russian Возвращает длину строки в символах.
inline size_t length() const {return len;}
//! \~english Returns characters length of string.
//! \~russian Возвращает длину строки в символах.
inline size_t size() const {return len;}
//! \~english Returns characters length of string.
//! \~russian Возвращает длину строки в символах.
inline ssize_t size_s() const {return len;}
//! \~english Returns if string starts with "str".
//! \~russian Возвращает начинается ли строка со "str".
bool startsWith(const PIConstChars & str) const;
//! \~english Returns if string ends with "str".
//! \~russian Возвращает оканчивается ли строка на "str".
bool endsWith(const PIConstChars & str) const;
//! \~english Returns part of string from character at index "start" and maximum length "len".
//! \~russian Возвращает подстроку от символа "start" и максимальной длиной "len".
//! \~\sa \a left(), \a right()
PIConstChars mid(const int start, const int len = -1) const;
//! \~english Returns part of string from start and maximum length "len".
//! \~russian Возвращает подстроку от начала и максимальной длиной "len".
//! \~\sa \a mid(), \a right()
PIConstChars left(const int len) const;
//! \~english Returns part of string at end and maximum length "len".
//! \~russian Возвращает подстроку максимальной длиной "len" и до конца.
//! \~\sa \a mid(), \a left()
PIConstChars right(const int len) const;
//! \~english Remove part of string from start and maximum length "len" and return this string.
//! \~russian Удаляет часть строки от начала и максимальной длины "len", возвращает эту строку.
//! \~\sa \a cutRight()
PIConstChars & cutLeft(const int len);
//! \~english Remove part of string at end and maximum length "len" and return this string.
//! \~russian Удаляет часть строки максимальной длины "len" от конца, возвращает эту строку.
//! \~\sa \a cutLeft()
PIConstChars & cutRight(const int len);
//! \~english Take a part from the begin of string with maximum length "len" and return it.
//! \~russian Извлекает часть строки от начала максимальной длины "len" и возвращает её.
//! \~\sa \a takeRight()
PIConstChars takeLeft(const int len);
//! \~english Take a part from the end of string with maximum length "len" and return it.
//! \~russian Извлекает часть строки с конца максимальной длины "len" и возвращает её.
//! \~\sa \a takeLeft()
PIConstChars takeRight(const int len);
//! \~english Remove spaces at the start and at the end of string and return this string.
//! \~russian Удаляет пробельные символы с начала и конца строки и возвращает эту строку.
//! \~\sa \a trimmed()
PIConstChars & trim();
//! \~english Returns copy of this string without spaces at the start and at the end.
//! \~russian Возвращает копию этой строки без пробельных символов с начала и конца.
//! \~\sa \a trim()
PIConstChars trimmed() const {return PIConstChars(*this).trim();}
//! \~english Returns as PIString.
//! \~russian Возвращает как PIString.
PIString toString() const;
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIConstChars & operator =(const PIConstChars & s) {
if (this == &s) return *this;
len = s.len;
str = s.str;
return *this;
}
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIConstChars & operator =(PIConstChars && s) {
swap(s);
return *this;
}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIConstChars & operator =(const char * s) {
str = s;
len = strlen(s);
return *this;
}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
inline bool operator ==(const PIConstChars & s) const {
if (isNull() && s.isNull()) return true;
if (isNull() xor s.isNull()) return false;
if (size() != s.size()) return false;
return strcmp(str, s.str) == 0;
}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
inline bool operator !=(const PIConstChars & s) const {return !(*this == s);}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
inline bool operator <(const PIConstChars & s) const {
if ( isNull() && s.isNull()) return false;
if ( isNull() && !s.isNull()) return true ;
if (!isNull() && s.isNull()) return false;
if (size() == s.size())
return strcmp(str, s.str) < 0;
return size() < s.size();
}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
inline bool operator >(const PIConstChars & s) const {
if ( isNull() && s.isNull()) return false;
if ( isNull() && !s.isNull()) return false;
if (!isNull() && s.isNull()) return true ;
if (size() == s.size())
return strcmp(str, s.str) > 0;
return size() > s.size();
}
//! \~english Returns hash of string content.
//! \~russian Возвращает хэш содержимого строки.
inline uint hash() const {
if (isEmpty()) return 0;
return piHashData((const uchar *)str, len);
}
inline void swap(PIConstChars& v) {
piSwap<const char *>(str, v.str);
piSwap<size_t>(len, v.len);
}
private:
const char * str = nullptr;
size_t len = 0;
};
//! \relatesalso PICout
//! \~english Output operator to \a PICout.
//! \~russian Оператор вывода в \a PICout.
inline PICout operator <<(PICout s, const PIConstChars & v) {
s.space();
if (v.isNull())
s.write("(null)");
else {
s.quote();
s.write(v.data(), v.size());
s.quote();
}
return s;
}
template<> inline uint piHash(const PIConstChars & s) {return s.hash();}
#endif // PICONSTCHARS_H

View File

@@ -16,6 +16,37 @@
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 Core Core
//! \~\brief
//! \~english Basic functionality.
//! \~russian Базовая функциональность.
//!
//! \~\details
//! \~english \section cmake_module_Core Building with CMake
//! \~russian \section cmake_module_Core Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides platform abstraction, useful macros, methods and classes
//!
//! \~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 PICOREMODULE_H
#define PICOREMODULE_H

View File

@@ -22,13 +22,94 @@
#include "pistack.h"
#include "piobject.h"
#include "pistring_std.h"
#ifdef HAS_LOCALE
# include <locale>
# include <codecvt>
#endif
#ifdef WINDOWS
# include <windows.h>
# include <wingdi.h>
# include <wincon.h>
# define COMMON_LVB_UNDERSCORE 0x8000
#endif
//! \addtogroup Core
//! \{
//! \~\class PICout picout.h
//! \~\brief
//! \~english Universal output to console class
//! \~russian Универсальный вывод в консоль
//!
//! \~english \section PICout_sec0 Synopsis
//! \~russian \section PICout_sec0 Краткий обзор
//! \~english
//! This class provide many stream operators for output with some features.
//! Output to %PICout is thread-sequential, i.e. doesn`t mixed from parallel
//! threads.
//!
//! \~russian
//! Данный класс предоставляет множество операторов для вывода в консоль.
//! Вывод в %PICout потоково-последовательный, т.е. не смешивается из параллельных
//! потоков.
//!
//! \~english \section PICout_sec1 Features
//! \~russian \section PICout_sec1 Особенности
//! \~english
//! * support text formatting (color, style)
//! * insertion spaces between entries
//! * insertion new line at the end of output
//! * strings are quoted
//! * custom output operator can be easily written
//! * can outpur to console, internal buffer or both
//!
//! \~russian
//! * поддержка форматирования (цвет, стиль)
//! * вставка пробелов между выводами
//! * вставка новой строки после последнего вывода
//! * строки обрамляются кавычками
//! * легко создавать сови операторы вывода
//! * может выводить в консоль, внутренний буфер или в оба места
//!
//! \~english \section PICout_ex0 Usage
//! \~russian \section PICout_ex0 Использование
//! \~\snippet picout.cpp 0
//!
//! \~english \section PICout_ex1 Writing your own output operator
//! \~russian \section PICout_ex1 Создание своего оператора вывода
//! \~\snippet picout.cpp own
//!
//! \}
//! \addtogroup Core
//! \{
//! \~\class PICout::Notifier picout.h
//! \~\brief
//! \~english Class for emit notifications of PICout
//! \~russian Класс для посылки событий от PICout
//!
//! \~english \section PICoutNotifier_sec0 Synopsis
//! \~russian \section PICoutNotifier_sec0 Краткий обзор
//! \~english
//! This class used as PICout events emitter. When
//! PICout constructs with external PIString* buffer
//! and some ID, last copy of this PICout on delete
//! emit event "finished()" on object Notifier::object().
//! Sample:
//!
//! \~russian
//! Этот класс используется как источник событий PICout.
//! Когда PICout сконструирован с внешним буфером PIString*
//! и каким-то ID, последняя копия этого PICout при уничтожении
//! посылает событие "finished()" у объекта Notifier::object().
//! Пример:
//!
//! \~\snippet picout.cpp notifier
//!
//! \}
class NotifierObject: public PIObject {
PIOBJECT(NotifierObject)
public:
@@ -78,15 +159,12 @@ WORD PICout::__Private__::dattr = 0;
DWORD PICout::__Private__::smode = 0;
#endif
PICout::PICout(PIFlags<PICoutControl> controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) {
init();
}
PICout::PICout(PICoutControl control): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(control) {
PICout::PICout(int controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) {
init();
}
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
buffer_ = nullptr;
if (act_)
init();
}
@@ -203,54 +281,96 @@ PICout PICout::operator <<(const PICoutAction v) {
}
#define PICOUTTOTARGET(v) { \
if (buffer_) {\
(*buffer_) << (v);\
} else {\
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
}\
PICout PICout::operator <<(const PICoutManipulators::PICoutFormat v) {
switch (v) {
case PICoutManipulators::Bin: cnb_ = 2; break;
case PICoutManipulators::Oct: cnb_ = 8; break;
case PICoutManipulators::Dec: cnb_ = 10; break;
case PICoutManipulators::Hex: cnb_ = 16; break;
default: applyFormat(v);
};
return *this;
}
#define PICOUTTOTARGETS(v) { \
if (buffer_) {\
(*buffer_) << (v);\
} else {\
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v).dataConsole();\
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
}\
}
#define PINUMERICCOUT if (cnb_ == 10) PICOUTTOTARGET(v) else PICOUTTOTARGETS(PIString::fromNumber(v, cnb_))
PICout PICout::operator <<(const char * v) {if (!act_) return *this; if (v[0] == '\0') return *this; space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
PICout PICout::operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v) {
if (v[PICoutManipulators::Bin]) cnb_ = 2;
if (v[PICoutManipulators::Oct]) cnb_ = 8;
if (v[PICoutManipulators::Dec]) cnb_ = 10;
if (v[PICoutManipulators::Hex]) cnb_ = 16;
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
if (v[PICoutManipulators::Underline]) applyFormat(PICoutManipulators::Underline);
if (v[PICoutManipulators::Blink]) applyFormat(PICoutManipulators::Blink);
if (v[PICoutManipulators::Black]) applyFormat(PICoutManipulators::Black);
if (v[PICoutManipulators::Red]) applyFormat(PICoutManipulators::Red);
if (v[PICoutManipulators::Green]) applyFormat(PICoutManipulators::Green);
if (v[PICoutManipulators::Blue]) applyFormat(PICoutManipulators::Blue);
if (v[PICoutManipulators::Yellow]) applyFormat(PICoutManipulators::Yellow);
if (v[PICoutManipulators::Magenta]) applyFormat(PICoutManipulators::Magenta);
if (v[PICoutManipulators::Cyan]) applyFormat(PICoutManipulators::Cyan);
if (v[PICoutManipulators::White]) applyFormat(PICoutManipulators::White);
if (v[PICoutManipulators::BackBlack]) applyFormat(PICoutManipulators::BackBlack);
if (v[PICoutManipulators::BackRed]) applyFormat(PICoutManipulators::BackRed);
if (v[PICoutManipulators::BackGreen]) applyFormat(PICoutManipulators::BackGreen);
if (v[PICoutManipulators::BackBlue]) applyFormat(PICoutManipulators::BackBlue);
if (v[PICoutManipulators::BackYellow]) applyFormat(PICoutManipulators::BackYellow);
if (v[PICoutManipulators::BackMagenta]) applyFormat(PICoutManipulators::BackMagenta);
if (v[PICoutManipulators::BackCyan]) applyFormat(PICoutManipulators::BackCyan);
if (v[PICoutManipulators::BackWhite]) applyFormat(PICoutManipulators::BackWhite);
if (v[PICoutManipulators::Default]) applyFormat(PICoutManipulators::Default);
return *this;
}
#define PICOUTTOTARGET(v) { \
if (buffer_) {\
(*buffer_) << (v);\
} else {\
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\
}\
}
#define PINUMERICCOUT(v) { \
if (!act_) return *this; \
space(); \
if (cnb_ == 10) PICOUTTOTARGET(v) \
else writePIString(PIString::fromNumber(v, cnb_)); \
return *this; \
}
PICout PICout::operator <<(const char * v) {if (!act_ || !v) return *this; if (v[0] == '\0') return *this; space(); quote(); PICOUTTOTARGET(v) quote(); return *this;}
PICout PICout::operator <<(const bool v) {if (!act_) return *this; space(); if (v) PICOUTTOTARGET("true") else PICOUTTOTARGET("false") return *this;}
PICout PICout::operator <<(const char v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const uchar v) {if (!act_) return *this; space(); if (cnb_ == 10) PICOUTTOTARGET(ushort(v)) else PICOUTTOTARGETS(PIString::fromNumber(v, cnb_)) return *this;}
PICout PICout::operator <<(const uchar v) {PINUMERICCOUT(ushort(v))}
PICout PICout::operator <<(const short int v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const short int v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const ushort v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ushort v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const int v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const int v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const uint v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const uint v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const long v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const long v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const ulong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ulong v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const llong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const llong v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const ullong v) {if (!act_) return *this; space(); PINUMERICCOUT return *this;}
PICout PICout::operator <<(const ullong v) {PINUMERICCOUT(v)}
PICout PICout::operator <<(const float v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const double v) {if (!act_) return *this; space(); PICOUTTOTARGET(v) return *this;}
PICout PICout::operator <<(const void * v) {if (!act_) return *this; space(); PICOUTTOTARGET("0x") PICOUTTOTARGETS(PIString::fromNumber(ullong(v), 16)) return *this;}
PICout PICout::operator <<(const void * v) {if (!act_) return *this; space(); PICOUTTOTARGET("0x") writePIString(PIString::fromNumber(ullong(v), 16)); return *this;}
PICout PICout::operator <<(const PIObject * v) {
if (!act_) return *this;
@@ -259,9 +379,9 @@ PICout PICout::operator <<(const PIObject * v) {
else {
PICOUTTOTARGET(v->className())
PICOUTTOTARGET("*(0x")
PICOUTTOTARGETS(PIString::fromNumber(ullong(v), 16))
writePIString(PIString::fromNumber(ullong(v), 16));
PICOUTTOTARGET(", \"")
PICOUTTOTARGET(v->name())
writePIString(v->name());
PICOUTTOTARGET("\")")
}
return *this;
@@ -272,10 +392,10 @@ PICout PICout::operator <<(const PICoutSpecialChar v) {
switch (v) {
case Null:
if (buffer_) {
(*buffer_) << PIChar(0);
(*buffer_) << PIChar();
} else {
if (isOutputDeviceActive(StdOut)) std::cout << char(0);
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(0);
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar();
}
break;
case NewLine:
@@ -345,6 +465,12 @@ PICout & PICout::restoreControl() {
#undef PICOUTTOTARGET
#undef PINUMERICCOUT
//! \details
//! \~english
//! If it is not a first output and control \a AddSpaces is set space character is put
//! \~russian
//! Добавляет пробел если это не первый вывод и установлен флаг \a AddSpaces
//! \~\sa \a quote(), \a newLine()
PICout & PICout::space() {
if (!act_) return *this;
if (!fo_ && co_[AddSpaces]) {
@@ -359,6 +485,12 @@ PICout & PICout::space() {
return *this;
}
//! \details
//! \~english
//! If control \a AddQuotes is set quote character is put
//! \~russian
//! Добавляет кавычки если установлен флаг \a AddQuotes
//! \~\sa \a space(), \a newLine()
PICout & PICout::quote() {
if (!act_) return *this;
if (co_[AddQuotes]) {
@@ -373,6 +505,12 @@ PICout & PICout::quote() {
return *this;
}
//! \details
//! \~english
//! If control \a AddNewLine is set new line character is put
//! \~russian
//! Добавляет новую строку если установлен флаг \a AddNewLine
//! \~\sa \a space(), \a quote()
PICout & PICout::newLine() {
if (!act_) return *this;
if (co_[AddNewLine]) {
@@ -388,6 +526,47 @@ PICout & PICout::newLine() {
}
PICout & PICout::write(const char * str) {
if (!act_ || !str) return *this;
return write(str, strlen(str));
}
PICout & PICout::write(const char * str, int len) {
if (!act_ || !str) return *this;
if (buffer_) {
buffer_->append(PIString(str, len));
} else {
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout.write(str, len);
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(PIString(str, len));
}
return *this;
}
PICout & PICout::writePIString(const PIString & s) {
if (!act_) return *this;
if (buffer_) {
buffer_->append(s);
} else {
if (PICout::isOutputDeviceActive(PICout::StdOut))
stdoutPIString(s);
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__().append(s);
}
return *this;
}
void PICout::stdoutPIString(const PIString & s) {
#ifdef HAS_LOCALE
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8conv;
std::cout << utf8conv.to_bytes((char16_t*)&(const_cast<PIString&>(s).front()), (char16_t*)&(const_cast<PIString&>(s).front()) + s.size());
#else
for (PIChar c: s) std::wcout.put(c.toWChar());
#endif
}
void PICout::init() {
#ifdef WINDOWS
if (__Private__::hOut == 0) {
@@ -398,7 +577,7 @@ void PICout::init() {
}
attr_ = __Private__::dattr;
#endif
buffer_ = 0;
buffer_ = nullptr;
id_ = 0;
if ((co_ & NoLock) != NoLock)
PICout::__mutex__().lock();

View File

@@ -1,5 +1,8 @@
/*! @file picout.h
* @brief Universal output to console class
/*! \file picout.h
* \ingroup Core
* \~\brief
* \~english Universal output to console class
* \~russian Универсальный вывод в консоль
*/
/*
PIP - Platform Independent Primitives
@@ -27,10 +30,13 @@
#ifdef DOXYGEN
//! @brief Macro used for conditional (piDebug) output to PICout
//! \~english Macro used for conditional (piDebug) output to PICout
//! \~russian Макрос для условного (piDebug) вывода в PICout
# define piCout
//! \relatesalso PIObject @brief Macro used for conditional (piDebug and PIObject::debug()) output to PICout for subclasses of PIObject
//! \relatesalso PIObject
//! \~english Macro used for conditional (piDebug && PIObject::debug()) output to PICout for subclasses of PIObject
//! \~russian Макрос для условного (piDebug && PIObject::debug()) вывода в PICout для наследников PIObject
# define piCoutObj
#else
@@ -42,106 +48,96 @@
class PIObject;
//! @brief Namespace contains enums controlled PICout
//! \relatesalso PICout
//! \~english Namespace contains enums that controls PICout
//! \~russian Пространство имен содержит перечисления для контроля PICout
namespace PICoutManipulators {
//! @brief Enum contains special characters
//! \~english Enum contains special characters
//! \~russian Перечисление со спецсимволами
enum PICoutSpecialChar {
Null /*! Null-character, '\\0' */,
NewLine /*! New line character, '\\n' */,
Tab /*! Tab character, '\\t' */,
Esc /*! Escape character, '\\e' */,
Quote /*! Quote character, '"' */
Null /*! \~english Null-character, '\\0' \~russian Нулевой символ, '\\0' */,
NewLine /*! \~english New line character, '\\n' \~russian Новая строка, '\\n' */,
Tab /*! \~english Tab character, '\\t' \~russian Табуляция, '\\t' */,
Esc /*! \~english Escape character, '\\e' \~russian Esc-символ, '\\e' */,
Quote /*! \~english Quote character, '\"' \~russian Кавычки, '\"' */
};
//! @brief Enum contains immediate action
//! \~english Enum contains immediate action
//! \~russian Перечисление с немедленными действиями
enum PICoutAction {
Flush /*! Flush the output */,
Backspace /*! Remove last symbol */,
ShowCursor /*! Show cursor */,
HideCursor /*! Hide cursor */,
ClearLine /*! Clear current line */,
ClearScreen /*! Clear the screen */,
SaveContol /*! Save control flags, equivalent to \a saveControl() */,
RestoreControl /*! Restore control flags, equivalent to \a restoreControl() */
Flush /*! \~english Flush the output \~russian Обновить вывод */,
Backspace /*! \~english Remove last symbol \~russian Удалить последний символ */,
ShowCursor /*! \~english Show cursor \~russian Показать курсор */,
HideCursor /*! \~english Hide cursor \~russian Скрыть курсор */,
ClearLine /*! \~english Clear current line \~russian Очистить текущую строку */,
ClearScreen /*! \~english Clear the screen \~russian Очистить экран */,
SaveContol /*! \~english Save control flags, equivalent to \a saveControl() \~russian Сохранить флаги, аналогично \a saveControl() */,
RestoreControl /*! \~english Restore control flags, equivalent to \a restoreControl() \~russian Восстановить флаги, аналогично \a restoreControl() */
};
//! @brief Enum contains control of PICout
//! \~english Enum contains control of PICout
//! \~russian Перечисление с управлением PICout
enum PICoutControl {
AddNone /*! No controls */ = 0x0,
AddSpaces /*! Spaces will be appear after each output */ = 0x1,
AddNewLine /*! New line will be appear after all output */ = 0x2,
AddQuotes /*! Each string will be quoted */ = 0x4,
DefaultControls /*! Default controls */ = AddSpaces | AddNewLine,
AddAll /*! All controls */ = 0xFF,
NoLock /*! Don`t use mutex for output */ = 0x100,
AddNone /*! \~english No controls \~russian Без управления */ = 0x0,
AddSpaces /*! \~english Spaces will be appear after each output \~russian Пробел после каждого вывода */ = 0x1,
AddNewLine /*! \~english New line will be appear after all output \~russian Новая строка после завершения вывода */ = 0x2,
AddQuotes /*! \~english Each string will be quoted \~russian Каждая строка в кавычках */ = 0x4,
DefaultControls /*! \~english Default controls \~russian Управление по умолчанию */ = AddSpaces | AddNewLine,
AddAll /*! \~english All controls \~russian Всё управление */ = 0xFF,
NoLock /*! \~english Don`t use mutex for output \~russian Не использовать мьютекс при выводе */ = 0x100,
};
//! @brief Enum contains output format
//! \~english Enum contains output format
//! \~russian Перечисление с форматом вывода
enum PICoutFormat {
Bin /*! Binary representation of integers */ = 0x01,
Oct /*! Octal representation of integers */ = 0x02,
Dec /*! Decimal representation of integers */ = 0x04,
Hex /*! Hexadecimal representation of integers */ = 0x08,
Bold /*! Bold */ = 0x10,
Faint /*! */ = 0x20,
Italic /*! */ = 0x40,
Underline /*! Underline */ = 0x80,
Blink /*! Blink */ = 0x100,
Black /*! Black font */ = 0x400,
Red /*! Red font */ = 0x800,
Green /*! Green font */ = 0x1000,
Blue /*! Blue font */ = 0x2000,
Yellow /*! Yellow font */ = 0x4000,
Magenta /*! Magenta font */ = 0x8000,
Cyan /*! Cyan font */ = 0x10000,
White /*! White font */ = 0x20000,
BackBlack /*! Black background */ = 0x40000,
BackRed /*! Red background */ = 0x80000,
BackGreen /*! Green background */ = 0x100000,
BackBlue /*! Blue background */ = 0x200000,
BackYellow /*! Yellow background */ = 0x400000,
BackMagenta /*! Magenta background */ = 0x800000,
BackCyan /*! Cyan background */ = 0x1000000,
BackWhite /*! White background */ = 0x2000000,
Default /*! Default format */ = 0x4000000
Bin /*! \~english Binary representation of integers \~russian Двоичное представление для целых чисел */ = 0x01,
Oct /*! \~english Octal representation of integers \~russian Восьмеричное представление для целых чисел */ = 0x02,
Dec /*! \~english Decimal representation of integers \~russian Десятичное представление для целых чисел */ = 0x04,
Hex /*! \~english Hexadecimal representation of integers \~russian Шестнадцатеричное представление для целых чисел */ = 0x08,
Bold /*! \~english Bold \~russian Жирный */ = 0x10,
Faint /*! \~english \~russian */ = 0x20,
Italic /*! \~english \~russian */ = 0x40,
Underline /*! \~english Underline \~russian Подчеркнутый */ = 0x80,
Blink /*! \~english Blink \~russian Мигающий */ = 0x100,
Black /*! \~english Black font \~russian Чёрный */ = 0x400,
Red /*! \~english Red font \~russian Красный */ = 0x800,
Green /*! \~english Green font \~russian Зелёный */ = 0x1000,
Blue /*! \~english Blue font \~russian Синий */ = 0x2000,
Yellow /*! \~english Yellow font \~russian Жёлтый */ = 0x4000,
Magenta /*! \~english Magenta font \~russian Пурпурный */ = 0x8000,
Cyan /*! \~english Cyan font \~russian Голубой */ = 0x10000,
White /*! \~english White font \~russian Белый */ = 0x20000,
BackBlack /*! \~english Black background \~russian Чёрный фон */ = 0x40000,
BackRed /*! \~english Red background \~russian Красный фон */ = 0x80000,
BackGreen /*! \~english Green background \~russian Зелёный фон */ = 0x100000,
BackBlue /*! \~english Blue background \~russian Синий фон */ = 0x200000,
BackYellow /*! \~english Yellow background \~russian Жёлтый фон */ = 0x400000,
BackMagenta /*! \~english Magenta background \~russian Пурпурный фон */ = 0x800000,
BackCyan /*! \~english Cyan background \~russian Голубой фон */ = 0x1000000,
BackWhite /*! \~english White background \~russian Белый фон */ = 0x2000000,
Default /*! \~english Default format \~russian Формат по умолчанию */ = 0x4000000
};
typedef PIFlags<PICoutControl> PICoutControls;
}
/*! \class PICout
* @brief Class for formatted output similar std::cout
*
* \section PICout_sec0 Synopsis
* This class provide many stream operators for output with some features.
* Output to PICout is thread-sequential, i.e. doesn`t mixed from parallel
* threads.
*
* \section PICout_sec1 Features
* - insertion spaces between entries
* - insertion new line at the end of output
* - strings are quoted
* - custom output operator can be easily written
*
* \section PICout_ex0 Usage
* \snippet picout.cpp 0
*
* \section PICout_ex1 Writing your own output operator
* \snippet picout.cpp own
*/
class PIP_EXPORT PICout {
public:
//! Default constructor with default features (AddSpaces and AddNewLine)
PICout(PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::DefaultControls);
PICout(PICoutManipulators::PICoutControl control = PICoutManipulators::DefaultControls);
//! Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
//! \~english Default constructor with default features (AddSpaces and AddNewLine)
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine)
PICout(int controls = PICoutManipulators::DefaultControls);
//! \~english Construct with default features (AddSpaces and AddNewLine), but if \"active\" is false does nothing
//! \~russian Конструктор по умолчанию (AddSpaces и AddNewLine), но если не \"active\" то будет неактивным
PICout(bool active);
//! Construct with external buffer and id "id". See \a Notifier for details
//! \~english Construct with external buffer and ID "id". See \a Notifier for details
//! \~russian Конструктор с внешним буфером и ID "id". Подробнее \a Notifier
PICout(PIString * buffer, int id = 0, PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces | PICoutManipulators::AddNewLine);
PICout(const PICout & other);
@@ -149,171 +145,187 @@ public:
~PICout();
/*! \class PICout::Notifier
* @brief Class for emit notifications of PICout
*
* \section PICout_sec0 Synopsis
* This class used as PICout events emitter. When
* PICout constructs with external PIString* buffer
* and some id, last copy of this PICout on delete
* emit event "finished()" on object Notifier::object().
* Sample:
* \snippet picout.cpp notifier
*/
class PIP_EXPORT Notifier {
public:
//! \~english Singleton access to %PICout::Notifier
//! \~russian Синглтон класса %PICout::Notifier
static Notifier * instance();
//! \~english Object that emit events from %PICout
//! \~russian Объект, который посылает события от %PICout
static PIObject * object();
private:
Notifier();
PIObject * o;
};
//! @brief Enum contains output devices of PICout
//! \~english Enum contains output devices of %PICout
//! \~russian Перечисление с устройствами вывода для %PICout
enum OutputDevice {
NoDevices /** PICout is disabled */ = 0x0,
StdOut /** Standard console output */ = 0x1,
Buffer /** Internal buffer */ = 0x2,
AllDevices /** All */ = 0xFFFF,
NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
StdOut /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
AllDevices /** \~english All \~russian Все */ = 0xFFFF,
};
typedef PIFlags<OutputDevice> OutputDevices;
//! Output operator for strings with <tt>"const char * "</tt> type
//! \~english Output operator for strings with <tt>"const char * "</tt> type
//! \~russian Оператор вывода для строк <tt>"const char * "</tt>
PICout operator <<(const char * v);
//! Output operator for strings with <tt>"std::string"</tt> type
// ! Output operator for strings with <tt>"std::string"</tt> type
//PICout operator <<(const std::string & v);
//! Output operator for boolean values
//! \~english Output operator for boolean values
//! \~russian Оператор вывода для логических значений
PICout operator <<(const bool v);
//! Output operator for <tt>"char"</tt> values
//! \~english Output operator for <tt>"char"</tt> values
//! \~russian Оператор вывода для <tt>"char"</tt> значений
PICout operator <<(const char v);
//! Output operator for <tt>"unsigned char"</tt> values
//! \~english Output operator for <tt>"unsigned char"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned char"</tt> значений
PICout operator <<(const uchar v);
//! Output operator for <tt>"short"</tt> values
//! \~english Output operator for <tt>"short"</tt> values
//! \~russian Оператор вывода для <tt>"short"</tt> значений
PICout operator <<(const short v);
//! Output operator for <tt>"unsigned short"</tt> values
//! \~english Output operator for <tt>"unsigned short"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned short"</tt> значений
PICout operator <<(const ushort v);
//! Output operator for <tt>"int"</tt> values
//! \~english Output operator for <tt>"int"</tt> values
//! \~russian Оператор вывода для <tt>"int"</tt> значений
PICout operator <<(const int v);
//! Output operator for <tt>"unsigned int"</tt> values
//! \~english Output operator for <tt>"unsigned int"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned int"</tt> значений
PICout operator <<(const uint v);
//! Output operator for <tt>"long"</tt> values
//! \~english Output operator for <tt>"long"</tt> values
//! \~russian Оператор вывода для <tt>"long"</tt> значений
PICout operator <<(const long v);
//! Output operator for <tt>"unsigned long"</tt> values
//! \~english Output operator for <tt>"unsigned long"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned long"</tt> значений
PICout operator <<(const ulong v);
//! Output operator for <tt>"long long"</tt> values
//! \~english Output operator for <tt>"long long"</tt> values
//! \~russian Оператор вывода для <tt>"long long"</tt> значений
PICout operator <<(const llong v);
//! Output operator for <tt>"unsigned long long"</tt> values
//! \~english Output operator for <tt>"unsigned long long"</tt> values
//! \~russian Оператор вывода для <tt>"unsigned long long"</tt> значений
PICout operator <<(const ullong v);
//! Output operator for <tt>"float"</tt> values
//! \~english Output operator for <tt>"float"</tt> values
//! \~russian Оператор вывода для <tt>"float"</tt> значений
PICout operator <<(const float v);
//! Output operator for <tt>"double"</tt> values
//! \~english Output operator for <tt>"double"</tt> values
//! \~russian Оператор вывода для <tt>"double"</tt> значений
PICout operator <<(const double v);
//! Output operator for pointers
//! \~english Output operator for pointers
//! \~russian Оператор вывода для указателей
PICout operator <<(const void * v);
//! Output operator for PIObject and ancestors
//! \~english Output operator for PIObject and ancestors
//! \~russian Оператор вывода для PIObject и наследников
PICout operator <<(const PIObject * v);
//! Output operator for \a PICoutSpecialChar values
//! \~english Output operator for \a PICoutSpecialChar values
//! \~russian Оператор вывода для \a PICoutSpecialChar
PICout operator <<(const PICoutManipulators::PICoutSpecialChar v);
//! Output operator for \a PIFlags<PICoutFormat> values
PICout operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v) {
if (v[PICoutManipulators::Bin]) cnb_ = 2;
if (v[PICoutManipulators::Oct]) cnb_ = 8;
if (v[PICoutManipulators::Dec]) cnb_ = 10;
if (v[PICoutManipulators::Hex]) cnb_ = 16;
if (v[PICoutManipulators::Bold]) applyFormat(PICoutManipulators::Bold);
if (v[PICoutManipulators::Faint]) applyFormat(PICoutManipulators::Faint);
if (v[PICoutManipulators::Italic]) applyFormat(PICoutManipulators::Italic);
if (v[PICoutManipulators::Underline]) applyFormat(PICoutManipulators::Underline);
if (v[PICoutManipulators::Blink]) applyFormat(PICoutManipulators::Blink);
if (v[PICoutManipulators::Black]) applyFormat(PICoutManipulators::Black);
if (v[PICoutManipulators::Red]) applyFormat(PICoutManipulators::Red);
if (v[PICoutManipulators::Green]) applyFormat(PICoutManipulators::Green);
if (v[PICoutManipulators::Blue]) applyFormat(PICoutManipulators::Blue);
if (v[PICoutManipulators::Yellow]) applyFormat(PICoutManipulators::Yellow);
if (v[PICoutManipulators::Magenta]) applyFormat(PICoutManipulators::Magenta);
if (v[PICoutManipulators::Cyan]) applyFormat(PICoutManipulators::Cyan);
if (v[PICoutManipulators::White]) applyFormat(PICoutManipulators::White);
if (v[PICoutManipulators::BackBlack]) applyFormat(PICoutManipulators::BackBlack);
if (v[PICoutManipulators::BackRed]) applyFormat(PICoutManipulators::BackRed);
if (v[PICoutManipulators::BackGreen]) applyFormat(PICoutManipulators::BackGreen);
if (v[PICoutManipulators::BackBlue]) applyFormat(PICoutManipulators::BackBlue);
if (v[PICoutManipulators::BackYellow]) applyFormat(PICoutManipulators::BackYellow);
if (v[PICoutManipulators::BackMagenta]) applyFormat(PICoutManipulators::BackMagenta);
if (v[PICoutManipulators::BackCyan]) applyFormat(PICoutManipulators::BackCyan);
if (v[PICoutManipulators::BackWhite]) applyFormat(PICoutManipulators::BackWhite);
if (v[PICoutManipulators::Default]) applyFormat(PICoutManipulators::Default);
return *this;
}
//! \~english Output operator for \a PIFlags<PICoutFormat> values
//! \~russian Оператор вывода для \a PIFlags<PICoutFormat>
PICout operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v);
//! Output operator for \a PICoutFormat values
PICout operator <<(const PICoutManipulators::PICoutFormat v) {
switch (v) {
case PICoutManipulators::Bin: cnb_ = 2; break;
case PICoutManipulators::Oct: cnb_ = 8; break;
case PICoutManipulators::Dec: cnb_ = 10; break;
case PICoutManipulators::Hex: cnb_ = 16; break;
default: applyFormat(v);
};
return *this;
}
//! \~english Output operator for \a PICoutFormat values
//! \~russian Оператор вывода для \a PICoutFormat
PICout operator <<(const PICoutManipulators::PICoutFormat v);
//! Do some action
//! \~english Do some action
//! \~russian Делает действие
PICout operator <<(const PICoutManipulators::PICoutAction v);
//! Set control flag "c" is "on" state
//! \~english Set control flag "c" is "on" state
//! \~russian Установить флаг "c" в "on" состояние
PICout & setControl(PICoutManipulators::PICoutControl c, bool on = true) {co_.setFlag(c, on); return *this;}
//! Set control flags "c" and if "save" exec \a saveControl()
//! \~english Set control flags "c" and if "save" exec \a saveControl()
//! \~russian Установить флаг "c" и если "save" то выполнить \a saveControl()
PICout & setControl(PICoutManipulators::PICoutControls c, bool save = false) {if (save) saveControl(); co_ = c; return *this;}
//! Save control flags to internal stack \sa \a restoreControl()
//! \~english Save control flags to internal stack
//! \~russian Сохраняет состояние флагов во внутренний стек
//! \~\sa \a restoreControl()
PICout & saveControl();
//! Restore control flags from internal stack \sa \a saveControl()
//! \~english Restore control flags from internal stack
//! \~russian Восстанавливает состояние флагов из внутреннего стека
//! \~\sa \a saveControl()
PICout & restoreControl();
/*! @brief Conditional put space character to output
* \details If it is not a first output and control \a AddSpaces is set
* space character is put \sa \a quote(), \a newLine() */
//! \~english Conditional put space character to output
//! \~russian Условно добавляет пробел
PICout & space();
/*! @brief Conditional put quote character to output
* \details If control \a AddQuotes is set
* quote character is put \sa \a space(), \a newLine() */
//! \~english Conditional put quote character to output
//! \~russian Условно добавляет кавычки
PICout & quote();
/*! @brief Conditional put new line character to output
* \details If control \a AddNewLine is set
* new line character is put \sa \a space(), \a quote() */
//! \~english Conditional put new line character to output
//! \~russian Условно добавляет новую строку
PICout & newLine();
//! \~english Write raw data
//! \~russian Пишет сырые символы
PICout & write(const char * str);
//! \~english Write raw data
//! \~russian Пишет сырые символы
PICout & write(const char * str, int len);
//! \~english Write raw \a PIString
//! \~russian Пишет сырой \a PIString
PICout & writePIString(const PIString & s);
//! \~english Output \a PIString to stdout
//! \~russian Вывод \a PIString в stdout
static void stdoutPIString(const PIString & s);
//! \~english Set output device to \a PICout::Buffer and if "clear" clear it
//! \~russian Устанавливает устройство вывода на \a PICout::Buffer и если "clear" то очищает его
static bool setBufferActive(bool on, bool clear = false);
//! \~english Equivalent to \a isOutputDeviceActive(OutputDevice)
//! \~russian Аналог \a isOutputDeviceActive(OutputDevice)
static bool isBufferActive();
//! \~english Returns internal PIString buffer and if "clear" clear it
//! \~russian Возвращает внутренний PIString буфер и если "clear" то очищает его
static PIString buffer(bool clear = false);
//! \~english Clear internal PIString buffer
//! \~russian Очищает внутренний PIString буфер
static void clearBuffer();
//! \~english Set output to device "d" enabled "on". Returns if it was enabled
//! \~russian Устройство вывода "d" устанавливается в "on". Возвращает было ли устройство активно
static bool setOutputDevice(OutputDevice d, bool on = true);
//! \~english Set output to devices to "d"
//! \~russian Устанавливает устройства вывода "d"
static void setOutputDevices(OutputDevices d);
//! \~english Returns if output device "d" is active
//! \~russian Возвращает активно ли устройство вывода "d"
static bool isOutputDeviceActive(OutputDevice d);
static PIMutex & __mutex__();

View File

@@ -0,0 +1,358 @@
/*
PIP - Platform Independent Primitives
Timer
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 "piincludes_p.h"
#include "pidatetime.h"
#include <ctime>
#ifdef ARDUINO
# include <Arduino.h>
#endif
#ifdef MAC_OS
//# include <mach/mach_traps.h>
//# include <mach/mach.h>
# include <mach/clock.h>
//# include <crt_externs.h>
#endif
#ifdef MICRO_PIP
# include <sys/time.h>
#endif
//! \addtogroup Core
//! \{
//! \~\class PITime pidatetime.h
//! \brief
//! \~english Calendar time
//! \~russian Календарное время
//!
//! \~\class PIDate pidatetime.h
//! \brief
//! \~english Calendar date
//! \~russian Календарная дата
//!
//! \~\class PIDateTime pidatetime.h
//! \brief
//! \~english Calendar date and time
//! \~russian Календарное дата и время
//!
//! \}
bool operator ==(const PITime & t0, const PITime & t1) {
return (t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
}
bool operator <(const PITime & t0, const PITime & t1) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds < t1.seconds;
} else return t0.minutes < t1.minutes;
} else return t0.hours < t1.hours;
}
bool operator >(const PITime & t0, const PITime & t1) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds > t1.seconds;
} else return t0.minutes > t1.minutes;
} else return t0.hours > t1.hours;
}
bool operator ==(const PIDate & t0, const PIDate & t1) {
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day);
}
bool operator <(const PIDate & t0, const PIDate & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
return t0.day < t1.day;
} else return t0.month < t1.month;
} else return t0.year < t1.year;
}
bool operator >(const PIDate & t0, const PIDate & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
return t0.day > t1.day;
} else return t0.month > t1.month;
} else return t0.year > t1.year;
}
bool operator ==(const PIDateTime & t0, const PIDateTime & t1) {
return (t0.year == t1.year && t0.month == t1.month && t0.day == t1.day &&
t0.hours == t1.hours && t0.minutes == t1.minutes && t0.seconds == t1.seconds);
}
bool operator <(const PIDateTime & t0, const PIDateTime & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
if (t0.day == t1.day) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds < t1.seconds;
} else return t0.minutes < t1.minutes;
} else return t0.hours < t1.hours;
} else return t0.day < t1.day;
} else return t0.month < t1.month;
} else return t0.year < t1.year;
}
bool operator >(const PIDateTime & t0, const PIDateTime & t1) {
if (t0.year == t1.year) {
if (t0.month == t1.month) {
if (t0.day == t1.day) {
if (t0.hours == t1.hours) {
if (t0.minutes == t1.minutes) {
return t0.seconds > t1.seconds;
} else return t0.minutes > t1.minutes;
} else return t0.hours > t1.hours;
} else return t0.day > t1.day;
} else return t0.month > t1.month;
} else return t0.year > t1.year;
}
PISystemTime PITime::toSystemTime() const {
return PISystemTime((hours * 60. + minutes) * 60. + seconds, milliseconds * 1000.);
}
PITime PITime::current() {
time_t rt = ::time(0);
tm * pt = localtime(&rt);
PITime t;
t.seconds = pt->tm_sec;
t.minutes = pt->tm_min;
t.hours = pt->tm_hour;
return t;
}
PITime PITime::fromSystemTime(const PISystemTime & st) {
double s = st.toSeconds();
int v = s;
PITime ret;
ret.milliseconds = (s - v) * 1000;
ret.seconds = v % 60; v = (v - ret.seconds) / 60;
ret.minutes = v % 60; v = (v - ret.minutes) / 60;
ret.hours = v;
return ret;
}
PIDate PIDate::current() {
time_t rt = ::time(0);
tm * pt = localtime(&rt);
PIDate d;
d.day = pt->tm_mday;
d.month = pt->tm_mon + 1;
d.year = pt->tm_year + 1900;
return d;
}
PIDateTime PIDateTime::current() {
time_t rt = ::time(0);
tm * pt = localtime(&rt);
PIDateTime dt;
dt.milliseconds = 0;
dt.seconds = pt->tm_sec;
dt.minutes = pt->tm_min;
dt.hours = pt->tm_hour;
dt.day = pt->tm_mday;
dt.month = pt->tm_mon + 1;
dt.year = pt->tm_year + 1900;
return dt;
}
PIString PITime::toString(const PIString & format) const {
PIString ts = format;
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(hours));
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(minutes));
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(seconds));
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
ts.replace("z", PIString::fromNumber(milliseconds));
return ts;
}
PIString PIDate::toString(const PIString & format) const {
PIString ts = format;
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(year).right(2));
ts.replace("y", PIString::fromNumber(year).right(1));
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(month));
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(day));
return ts;
}
PIString PIDateTime::toString(const PIString & format) const {
PIString ts = format;
ts.replace("yyyy", PIString::fromNumber(year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(year).right(2));
ts.replace("y", PIString::fromNumber(year).right(1));
ts.replace("MM", PIString::fromNumber(month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(month));
ts.replace("dd", PIString::fromNumber(day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(day));
ts.replace("hh", PIString::fromNumber(hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(hours));
ts.replace("mm", PIString::fromNumber(minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(minutes));
ts.replace("ss", PIString::fromNumber(seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(seconds));
ts.replace("zzz", PIString::fromNumber(milliseconds).expandLeftTo(3, '0'));
ts.replace("zz", PIString::fromNumber(milliseconds).expandLeftTo(2, '0'));
ts.replace("z", PIString::fromNumber(milliseconds));
return ts;
}
time_t PIDateTime::toSecondSinceEpoch() const {
tm pt;
memset(&pt, 0, sizeof(pt));
pt.tm_sec = seconds;
pt.tm_min = minutes;
pt.tm_hour = hours;
pt.tm_mday = day;
pt.tm_mon = month - 1;
#ifdef WINDOWS
pt.tm_year = piMaxi(year - 1900, 70);
#else
pt.tm_year = piMaxi(year - 1900, 0);
#endif
return mktime(&pt);
}
PIDateTime PIDateTime::fromSecondSinceEpoch(const time_t sec) {
tm * pt = localtime(&sec);
PIDateTime dt;
dt.seconds = pt->tm_sec;
dt.minutes = pt->tm_min;
dt.hours = pt->tm_hour;
dt.day = pt->tm_mday;
dt.month = pt->tm_mon + 1;
dt.year = pt->tm_year + 1900;
return dt;
}
PIString time2string(const PITime & time, const PIString & format) {
PIString ts = format;
ts.replace("hh", PIString::fromNumber(time.hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(time.hours));
ts.replace("mm", PIString::fromNumber(time.minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(time.minutes));
ts.replace("ss", PIString::fromNumber(time.seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(time.seconds));
return ts;
}
PIString date2string(const PIDate & date, const PIString & format) {
PIString ts = format;
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(date.year).right(2));
ts.replace("y", PIString::fromNumber(date.year).right(1));
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(date.month));
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(date.day));
return ts;
}
PIString datetime2string(const PIDateTime & date, const PIString & format) {
PIString ts = format;
ts.replace("hh", PIString::fromNumber(date.hours).expandLeftTo(2, '0'));
ts.replace("h", PIString::fromNumber(date.hours));
ts.replace("mm", PIString::fromNumber(date.minutes).expandLeftTo(2, '0'));
ts.replace("m", PIString::fromNumber(date.minutes));
ts.replace("ss", PIString::fromNumber(date.seconds).expandLeftTo(2, '0'));
ts.replace("s", PIString::fromNumber(date.seconds));
ts.replace("yyyy", PIString::fromNumber(date.year).expandLeftTo(4, '0'));
ts.replace("yy", PIString::fromNumber(date.year).right(2));
ts.replace("y", PIString::fromNumber(date.year).right(1));
ts.replace("MM", PIString::fromNumber(date.month).expandLeftTo(2, '0'));
ts.replace("M", PIString::fromNumber(date.month));
ts.replace("dd", PIString::fromNumber(date.day).expandLeftTo(2, '0'));
ts.replace("d", PIString::fromNumber(date.day));
return ts;
}
PICout operator <<(PICout s, const PITime & v) {
s.space();
s.setControl(0, true);
s << "PITime(" << v.hours << ":";
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
s.restoreControl();
return s;
}
PICout operator <<(PICout s, const PIDate & v) {
s.space();
s.setControl(0, true);
s << "PIDate(" << v.day << "-";
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
s << v.year << ")";
s.restoreControl();
return s;
}
PICout operator <<(PICout s, const PIDateTime & v) {
s.space();
s.setControl(0, true);
s << "PIDateTime(";
s << v.day << "-";
s << PIString::fromNumber(v.month).expandLeftTo(2, '0') << "-";
s << v.year << " ";
s << v.hours << ":";
s << PIString::fromNumber(v.minutes).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.seconds).expandLeftTo(2, '0') << ":";
s << PIString::fromNumber(v.milliseconds).expandLeftTo(3, '0') << ")";
s.restoreControl();
return s;
}

318
libs/main/core/pidatetime.h Normal file
View File

@@ -0,0 +1,318 @@
/*! \file pidatetime.h
* \ingroup Core
* \~\brief
* \~english Time and date structs
* \~russian Типы времени и даты
*/
/*
PIP - Platform Independent Primitives
Time and date 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 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 PIDATETIME_H
#define PIDATETIME_H
#include "pisystemtime.h"
class PIP_EXPORT PITime {
public:
//! \~english Construct %PITime from hours, minutes, seconds and milliseconds
//! \~russian Создает %PITime из часов, минут, секунд и миллисекунд
PITime(int hours_ = 0, int minutes_ = 0, int seconds_ = 0, int milliseconds_ = 0): hours(hours_), minutes(minutes_), seconds(seconds_), milliseconds(milliseconds_) {;}
//! \~english Returns string representation
//! \~russian Возвращает строковое представление
PIString toString(const PIString & format = "h:mm:ss") const;
//! \~english Returns time as %PISystemTime
//! \~russian Возвращает время как %PISystemTime
PISystemTime toSystemTime() const;
//! \~english Returns current time
//! \~russian Возвращает текущее время
static PITime current();
//! \~english Construct %PITime from %PISystemTime
//! \~russian Создает %PITime из %PISystemTime
static PITime fromSystemTime(const PISystemTime & st);
//! \~english Hour, 0-23
//! \~russian Час, 0-23
int hours;
//! \~english Minutes, 0-59
//! \~russian Минуты, 0-59
int minutes;
//! \~english Seconds, 0-59
//! \~russian Секунды, 0-59
int seconds;
//! \~english Milliseconds, 0-999
//! \~russian Миллисекунды, 0-999
int milliseconds;
};
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator ==(const PITime & t0, const PITime & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator <(const PITime & t0, const PITime & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator >(const PITime & t0, const PITime & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator !=(const PITime & t0, const PITime & t1) {return !(t0 == t1);}
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const PITime & t0, const PITime & t1) {return !(t0 > t1);}
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const PITime & t0, const PITime & t1) {return !(t0 < t1);}
//! \relatesalso PICout
//! \~english \brief Output operator to PICout
//! \~russian \brief Оператор вывода в PICout
PIP_EXPORT PICout operator <<(PICout s, const PITime & v);
class PIP_EXPORT PIDate {
public:
//! \~english Construct %PIDate from year, month and day
//! \~russian Создает %PIDate из года, месяца и дня
PIDate(int year_ = 0, int month_ = 0, int day_ = 0): year(year_), month(month_), day(day_) {;}
//! \~english Returns string representation
//! \~russian Возвращает строковое представление
PIString toString(const PIString & format = "d.MM.yyyy") const;
//! \~english Returns current date
//! \~russian Возвращает текущую дату
static PIDate current();
//! \~english Year
//! \~russian Год
int year;
//! \~english Month, 1-12
//! \~russian Месяц, 1-12
int month;
//! \~english Day, 1-31
//! \~russian День, 1-31
int day;
};
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator ==(const PIDate & t0, const PIDate & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator <(const PIDate & t0, const PIDate & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator >(const PIDate & t0, const PIDate & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator !=(const PIDate & t0, const PIDate & t1) {return !(t0 == t1);}
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const PIDate & t0, const PIDate & t1) {return !(t0 > t1);}
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const PIDate & t0, const PIDate & t1) {return !(t0 < t1);}
//! \relatesalso PICout
//! \~english \brief Output operator to PICout
//! \~russian \brief Оператор вывода в PICout
PIP_EXPORT PICout operator <<(PICout s, const PIDate & v);
class PIP_EXPORT PIDateTime {
public:
//! \~english Construct null %PIDateTime
//! \~russian Создает нулевой %PIDateTime
PIDateTime() {year = month = day = hours = minutes = seconds = milliseconds = 0;}
//! \~english Construct %PIDateTime from %PITime and null %PIDate
//! \~russian Создает %PIDateTime из %PITime и нулевого %PIDate
PIDateTime(const PITime & time) {year = month = day = 0; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
//! \~english Construct %PIDateTime from %PIDate and null %PITime
//! \~russian Создает %PIDateTime из %PIDate и нулевого %PITime
PIDateTime(const PIDate & date) {year = date.year; month = date.month; day = date.day; hours = minutes = seconds = milliseconds = 0;}
//! \~english Construct %PIDateTime from %PIDate and %PITime
//! \~russian Создает %PIDateTime из %PIDate и %PITime
PIDateTime(const PIDate & date, const PITime & time) {year = date.year; month = date.month; day = date.day; hours = time.hours; minutes = time.minutes; seconds = time.seconds; milliseconds = time.milliseconds;}
//! \~english Returns normalized %PIDateTime
//! \~russian Возвращает нормализованный %PIDateTime
PIDateTime normalized() const {return PIDateTime::fromSecondSinceEpoch(toSecondSinceEpoch());}
//! \~english Normalize all fields
//! \~russian Нормализует все поля
void normalize() {*this = normalized();}
//! \~english Returns string representation
//! \~russian Возвращает строковое представление
PIString toString(const PIString & format = "h:mm:ss d.MM.yyyy") const;
//! \~english Returns seconds since 1 Jan 1970
//! \~russian Возвращает секунды от 1 Янв 1970
time_t toSecondSinceEpoch() const;
//! \~english Returns time as %PISystemTime
//! \~russian Возвращает время как %PISystemTime
PISystemTime toSystemTime() const {return PISystemTime(int(toSecondSinceEpoch()), milliseconds * 1000000);}
//! \~english Returns date part
//! \~russian Возвращает дату
PIDate date() const {return PIDate(year, month, day);}
//! \~english Returns time part
//! \~russian Возвращает время
PITime time() const {return PITime(hours, minutes, seconds, milliseconds);}
//! \~english Set date part
//! \~russian Устанавливает дату
void setDate(const PIDate & d) {year = d.year; month = d.month; day = d.day;}
//! \~english Set time part
//! \~russian Устанавливает время
void setTime(const PITime & t) {hours = t.hours; minutes = t.minutes; seconds = t.seconds; milliseconds = t.milliseconds;}
//! \~english Sum operator
//! \~russian Оператор сложения
void operator +=(const PIDateTime & d1) {year += d1.year; month += d1.month; day += d1.day; hours += d1.hours; minutes += d1.minutes; seconds += d1.seconds; normalize();}
//! \~english Subtract operator
//! \~russian Оператор вычитания
void operator -=(const PIDateTime & d1) {year -= d1.year; month -= d1.month; day -= d1.day; hours -= d1.hours; minutes -= d1.minutes; seconds -= d1.seconds; normalize();}
//! \~english Construct %PIDateTime from seconds since 1 Jan 1970
//! \~russian Создает %PIDateTime из секунд от 1 Янв 1970
static PIDateTime fromSecondSinceEpoch(const time_t sec);
//! \~english Construct %PIDateTime from %PISystemTime
//! \~russian Создает %PIDateTime из %PISystemTime
static PIDateTime fromSystemTime(const PISystemTime & st) {PIDateTime dt = fromSecondSinceEpoch(st.seconds); dt.milliseconds = piClampi(st.nanoseconds / 1000000, 0, 999); return dt;}
//! \~english Returns current date and time
//! \~russian Возвращает текущую дату и время
static PIDateTime current();
//! \~english Year
//! \~russian Год
int year;
//! \~english Month, 1-12
//! \~russian Месяц, 1-12
int month;
//! \~english Day, 1-31
//! \~russian День, 1-31
int day;
//! \~english Hour, 0-23
//! \~russian Час, 0-23
int hours;
//! \~english Minutes, 0-59
//! \~russian Минуты, 0-59
int minutes;
//! \~english Seconds, 0-59
//! \~russian Секунды, 0-59
int seconds;
//! \~english Milliseconds, 0-999
//! \~russian Миллисекунды, 0-999
int milliseconds;
};
//! \~english Sum operator
//! \~russian Оператор сложения
inline PIDateTime operator +(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td += d1; return td.normalized();}
//! \~english Subtract operator
//! \~russian Оператор вычитания
inline PIDateTime operator -(const PIDateTime & d0, const PIDateTime & d1) {PIDateTime td = d0; td -= d1; return td.normalized();}
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator ==(const PIDateTime & t0, const PIDateTime & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator <(const PIDateTime & t0, const PIDateTime & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
PIP_EXPORT bool operator >(const PIDateTime & t0, const PIDateTime & t1);
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator !=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 == t1);}
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 > t1);}
//! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const PIDateTime & t0, const PIDateTime & t1) {return !(t0 < t1);}
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const PIDateTime & v) {s << v.year << v.month << v.day << v.hours << v.minutes << v.seconds << v.milliseconds; return s;}
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, PIDateTime & v) {s >> v.year >> v.month >> v.day >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;}
//! \relatesalso PICout
//! \~english \brief Output operator to PICout
//! \~russian \brief Оператор вывода в PICout
PIP_EXPORT PICout operator <<(PICout s, const PIDateTime & v);
#endif // PIDATETIME_H

View File

@@ -1,5 +1,8 @@
/*! @file piflags.h
* @brief General flags class
/*! \file piflags.h
* \ingroup Core
* \~\brief
* \~english General flags class
* \~russian Универсальные флаги
*/
/*
PIP - Platform Independent Primitives
@@ -25,109 +28,220 @@
#include "pip_export.h"
/*! @brief This class used as container for bit flags
* \details PIFlags is wrapper around \c "int". There are many
* bit-wise operators, native conversion to int and function
* to test flag. \n Example:
* \snippet piincludes.cpp flags
*/
//! \addtogroup Core
//! \{
//! \~\class PIFlags piflags.h
//! \~\brief
//! \~english Container for bit flags
//! \~russian Контейнер для битовых полей (флагов)
//!
//! \~\details
//! \~english
//! %PIFlags is wrapper around \c "int". One can use it as native \c "int".
//! There are manybit-wise operators,
//! native conversion to "int" and function
//! to test flag. \n Example:
//!
//! \~russian
//! %PIFlags по сути обертка вокруг \c "int". Можно использовать его как обычный \c "int".
//! Имеет много битовых операторов,
//! неявное преобразование в "int" и методы для проверки
//! флагов. \n Пример:
//!
//! \~\snippet piincludes.cpp flags
//!
//! \}
template<typename Enum>
class PIFlags {
public:
//! Constructor with flags = 0
//! \~english Constructor with flags = 0
//! \~russian Создает нулевые флаги
PIFlags(): flags(0) {;}
//! Constructor with flags = Enum "e"
//! \~english Constructor with flags = Enum "e"
//! \~russian Создает флаги со значением = Enum "e"
PIFlags(Enum e): flags(e) {;}
//! Constructor with flags = int "i"
//! \~english Constructor with flags = int "i"
//! \~russian Создает флаги со значением = int "i"
PIFlags(const int i): flags(i) {;}
//! Set flags "f" to value "on"
//! \~english Set flags on positions "f" to value "on"
//! \~russian Устанавливает флаги по позициям "f" в "on"
PIFlags & setFlag(const PIFlags & f, bool on = true) {if (on) flags |= f.flags; else flags &= ~f.flags; return *this;}
//! Set flag "e" to value "on"
//! \~english Set flag "e" to value "on"
//! \~russian Устанавливает флаг "e" в "on"
PIFlags & setFlag(const Enum & e, bool on = true) {if (on) flags |= e; else flags &= ~e; return *this;}
//! Set flag "i" to value "on"
//! \~english Set flag "i" to value "on"
//! \~russian Устанавливает флаг "i" в "on"
PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;}
//! copy operator
//! \~english Assign operator
//! \~russian Оператор присваивания
void operator =(const Enum & e) {flags = e;}
//! copy operator
//! \~english Assign operator
//! \~russian Оператор присваивания
void operator =(const int & i) {flags = i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const PIFlags & f) {return flags == f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const Enum & e) {return flags == e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const int i) {return flags == i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const PIFlags & f) {return flags != f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const Enum & e) {return flags != e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const int i) {return flags != i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const PIFlags & f) {return flags > f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const Enum & e) {return flags > e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const int i) {return flags > i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const PIFlags & f) {return flags < f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const Enum & e) {return flags < e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const int i) {return flags < i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const PIFlags & f) {return flags >= f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const Enum & e) {return flags >= e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const int i) {return flags >= i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const PIFlags & f) {return flags <= f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const Enum & e) {return flags <= e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const int i) {return flags <= i;}
//! Bit-wise AND operator
//! \~english Bit-wise AND operator
//! \~russian Оператор побитового И
void operator &=(const PIFlags & f) {flags &= f.flags;}
//! Bit-wise AND operator
//! \~english Bit-wise AND operator
//! \~russian Оператор побитового И
void operator &=(const Enum & e) {flags &= e;}
//! Bit-wise AND operator
//! \~english Bit-wise AND operator
//! \~russian Оператор побитового И
void operator &=(const int i) {flags &= i;}
//! Bit-wise OR operator
//! \~english Bit-wise OR operator
//! \~russian Оператор побитового ИЛИ
void operator |=(const PIFlags & f) {flags |= f.flags;}
//! Bit-wise OR operator
//! \~english Bit-wise OR operator
//! \~russian Оператор побитового ИЛИ
void operator |=(const Enum & e) {flags |= e;}
//! Bit-wise OR operator
//! \~english Bit-wise OR operator
//! \~russian Оператор побитового ИЛИ
void operator |=(const int i) {flags |= i;}
//! Bit-wise XOR operator
//! \~english Bit-wise XOR operator
//! \~russian Оператор побитового исключающего ИЛИ
void operator ^=(const PIFlags & f) {flags ^= f.flags;}
//! Bit-wise XOR operator
//! \~english Bit-wise XOR operator
//! \~russian Оператор побитового исключающего ИЛИ
void operator ^=(const Enum & e) {flags ^= e;}
//! Bit-wise XOR operator
//! \~english Bit-wise XOR operator
//! \~russian Оператор побитового исключающего ИЛИ
void operator ^=(const int i) {flags ^= i;}
//! Bit-wise AND operator
//! \~english Bit-wise AND operator
//! \~russian Оператор побитового И
PIFlags operator &(PIFlags f) const {PIFlags tf(flags & f.flags); return tf;}
//! Bit-wise AND operator
//! \~english Bit-wise AND operator
//! \~russian Оператор побитового И
PIFlags operator &(Enum e) const {PIFlags tf(flags & e); return tf;}
//! Bit-wise AND operator
//! \~english Bit-wise AND operator
//! \~russian Оператор побитового И
PIFlags operator &(int i) const {PIFlags tf(flags & i); return tf;}
//! Bit-wise OR operator
//! \~english Bit-wise OR operator
//! \~russian Оператор побитового ИЛИ
PIFlags operator |(PIFlags f) const {PIFlags tf(flags | f.flags); return tf;}
//! Bit-wise OR operator
//! \~english Bit-wise OR operator
//! \~russian Оператор побитового ИЛИ
PIFlags operator |(Enum e) const {PIFlags tf(flags | e); return tf;}
//! Bit-wise OR operator
//! \~english Bit-wise OR operator
//! \~russian Оператор побитового ИЛИ
PIFlags operator |(int i) const {PIFlags tf(flags | i); return tf;}
//! Bit-wise XOR operator
//! \~english Bit-wise XOR operator
//! \~russian Оператор побитового исключающего ИЛИ
PIFlags operator ^(PIFlags f) const {PIFlags tf(flags ^ f.flags); return tf;}
//! Bit-wise XOR operator
//! \~english Bit-wise XOR operator
//! \~russian Оператор побитового исключающего ИЛИ
PIFlags operator ^(Enum e) const {PIFlags tf(flags ^ e); return tf;}
//! Bit-wise XOR operator
//! \~english Bit-wise XOR operator
//! \~russian Оператор побитового исключающего ИЛИ
PIFlags operator ^(int i) const {PIFlags tf(flags ^ i); return tf;}
//! Test flag operator
//! \~english Test flag operator
//! \~russian Оператор проверки флага
bool operator [](Enum e) const {return (flags & e) == e;}
//! Implicity conversion to \c int
//! \~english Implicity conversion to \c int
//! \~russian Оператор неявного преобразования в \c int
operator int() const {return flags;}
private:
int flags;
};
#endif // PIFLAGS_H

View File

@@ -64,10 +64,16 @@ void errorClear() {
PIString errorString() {
#ifdef WINDOWS
char * msg;
char * msg = nullptr;
int err = GetLastError();
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msg, 0, NULL);
return "code " + PIString::fromNumber(err) + " - " + PIString(msg);
PIString ret = PIStringAscii("code ") + PIString::fromNumber(err) + PIStringAscii(" - ");
if (msg) {
ret += PIString::fromSystem(msg).trim();
LocalFree(msg);
} else
ret += '?';
return ret;
#else
int e = errno;
return PIString("code ") + PIString::fromNumber(e) + " - " + PIString(strerror(e));
@@ -80,11 +86,6 @@ PIString PIPVersion() {
}
void piqsort(void * base, size_t num, size_t size, int (*compar)(const void *, const void *)) {
qsort(base, num, size, compar);
}
void randomize() {
srand(PISystemTime::current(true).nanoseconds);
}
@@ -95,7 +96,10 @@ int randomi() {
}
/*! \mainpage What is PIP
/*! \~english \mainpage What is PIP
* \~russian \mainpage Что такое PIP
*
* \~english
* PIP - Platform-Independent Primitives - is crossplatform library for C++ developers.
* It is wrap around STL and pure C++. This library can help developers write non-GUI
* projects much more quickly, efficiently and customizable than on pure C++.
@@ -112,10 +116,16 @@ int randomi() {
* * executor (\a PIThreadPoolExecutor)
* * blocking dequeue (\a PIBlockingDequeue)
* * timer (\a PITimer)
* * console (information output) (\a PIConsole)
* * stand-alone
* * server
* * client
* * 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)
@@ -134,15 +144,72 @@ int randomi() {
* * peering net node (\a PIPeer)
* * process (\a PIProcess)
* * state machine (\a PIStateMachine)
* \n \n Basic using of PIP described at page \ref using_basic */
* \n \n Basic using of PIP described at page \ref using_basic
*
* \~russian
* PIP - Platform-Independent Primitives - кроссплатформенная библиотека для разработчиков на C++.
* It is wrap around STL and pure C++. This library can help developers write non-GUI
* projects much more quickly, efficiently and customizable than on pure C++.
* PIP предоставляет следующие классы:
* * общение с консолью (\a PICout)
* * контейнеры (\a PIVector, \a PIList, \a PIMap, \a PIStack)
* * байтовый массив (\a PIByteArray)
* * строка (\a PIString, \a PIStringList)
* * базовый объект (события и обработчики) (\a PIObject)
* * многопоточность
* * поток (\a PIThread)
* * исполнитель (\a PIThreadPoolExecutor)
* * блокирующая очередь (\a PIBlockingDequeue)
* * таймер (\a PITimer)
* * тайлинговая консоль (с виджетами) (\a PIScreen)
* * простой вывод строк
* * скроллбар
* * лист
* * кнопка
* * группа кнопок
* * галочка
* * прогрессбар
* * вывод PICout
* * текстовый ввод
* * устройства ввода/вывода
* * базовый класс (\a PIIODevice)
* * файл (\a PIFile)
* * последовательный порт (\a PISerial)
* * ethernet (\a PIEthernet)
* * USB (\a PIUSB)
* * packets extractor (\a PIPacketExtractor)
* * бинарный логфайл (\a PIBinaryLog)
* * сложное составное устройство (\a PIConnection)
* * поддержка библиотек времени выполнения
* * базовая функциональность (\a PILibrary)
* * плагин (\a PIPluginLoader)
* * диагностика качества связи (\a PIDiagnostics)
* * парсер аргументов командной строки (\a PICLI)
* * вычислитель (\a PIEvaluator)
* * пиринговая сеть (\a PIPeer)
* * процесс (\a PIProcess)
* * машина состояний (\a PIStateMachine)
* \n \n Базовое использование PIP описано на странице \ref using_basic
*/
/*! \page using_basic Getting started
/*! \~english \page using_basic Getting started
* \~russian \page using_basic Простые начала
*
* \~english
* Many novice programmers are solved many common task with system integrity: output to console,
* 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>
@@ -232,15 +299,32 @@ int main(int argc, char * argv[]) {
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 */
* \n If you want more information see \ref using_advanced
*
* \~russian
* Этот код демонстрирует простую конфигурируемую программу, которая может быть запущена с
* This code demonstrates simple interactive configurable program, which can be started with console
* display or not, and with debug or not. \b MainClass is central class that also can be inherited from
* \a PIThread and reimplement \a run() function.
* \n Many PIP classes has events and event handlers, which can be connected one to another.
* Details you can see at \a PIObject reference page (\ref PIObject_sec0).
* \n To configure your program from file use \a PIConfig.
*/
/*! \page using_advanced Advanced using
* Sorry, creativity crysis xD
*/
/*
* \~english
* \~russian
*/

View File

@@ -1,3 +1,9 @@
/*! \file piincludes.h
* \ingroup Core
* \~\brief
* \~english Minimal PIP includes
* \~russian Минимально-необходимые инклюды PIP
*/
/*
PIP - Platform Independent Primitives
Minimal PIP includes
@@ -26,15 +32,15 @@
#ifdef PIP_STD_IOSTREAM
# include <iostream>
#endif
#include <atomic>
class PIMutex;
class PIMutexLocker;
class PIObject;
class PIString;
class PIByteArray;
#ifndef MICRO_PIP
class PIInit;
#endif
class PIChar;
class PICout;
@@ -42,18 +48,29 @@ struct lconv;
extern PIP_EXPORT lconv * currentLocale;
/*! \fn errorString()
* @brief Return readable error description in format "code <number> - <description>" */
//! \ingroup Core
//! \brief
//! \~english
//! Return readable error description in format "code <number> - <description>"
//! \~russian
//! Возвращает читаемое описание ошибки в формате "code <номер> - <описание>"
PIP_EXPORT PIString errorString();
//! \ingroup Core
//! \brief
//! \~english
//! Reset last error
//! \~russian
//! Сброс последней ошибки
PIP_EXPORT void errorClear();
PIP_EXPORT void piqsort(void* base, size_t num, size_t size, int (*compar)(const void*,const void*));
PIP_EXPORT void randomize();
PIP_EXPORT int randomi();
/// Return readable version of PIP
//! \ingroup Core
//! \brief
//! \~english Return readable version of PIP
//! \~russian Возвращает читаемую версию PIP
PIP_EXPORT PIString PIPVersion();
#endif // PIINCLUDES_H

View File

@@ -40,6 +40,15 @@ typedef LONG(NTAPI*PINtSetTimerResolution)(ULONG, BOOLEAN, PULONG);
#include <cstdio>
#include <iostream>
#ifdef FREERTOS
# ifdef ESP_PLATFORM
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
# endif
# ifdef ARDUINO_ARCH_STM32
# include <STM32FreeRTOS.h>
# endif
#endif
#endif // PIINCLUDES_P_H

View File

@@ -19,18 +19,19 @@
#include "piincludes_p.h"
#include "piinit.h"
#ifndef MICRO_PIP
#include "pitime.h"
#include "pisignals.h"
#include "piobject.h"
#include "pisysteminfo.h"
#include "piresourcesstorage.h"
#include "pidir.h"
#ifndef FREERTOS
# include "piprocess.h"
#endif
#include "piprocess.h"
#ifdef ESP_PLATFORM
# include "esp_system.h"
#endif
#include <codecvt>
#ifdef WINDOWS
# include <winsock2.h>
extern FILETIME __pi_ftjan1970;
@@ -49,9 +50,7 @@ void __PISetTimerResolution() {
}
#else
# include <pwd.h>
# ifndef FREERTOS
# include <sys/utsname.h>
# endif
# include <sys/utsname.h>
# include <pthread.h>
# ifdef BLACKBERRY
# include <signal.h>
@@ -84,7 +83,6 @@ ULONG prev_res;
bool delete_locs;
PRIVATE_DEFINITION_END(PIInit)
#ifndef FREERTOS
void __sighandler__(PISignals::Signal s) {
//piCout << Hex << int(s);
if (s == PISignals::StopTTYInput || s == PISignals::StopTTYOutput)
@@ -92,7 +90,6 @@ void __sighandler__(PISignals::Signal s) {
if (s == PISignals::UserDefined1)
dumpApplicationToFile(PIDir::home().path() + PIDir::separator + PIStringAscii("_PIP_DUMP_") + PIString::fromNumber(PIProcess::currentPID()));
}
#endif
#ifdef ANDROID
@@ -107,7 +104,6 @@ PIInit::PIInit() {
PISystemInfo * sinfo = PISystemInfo::instance();
sinfo->execDateTime = PIDateTime::current();
setFileCharset("UTF-8");
#ifndef FREERTOS
#ifndef ANDROID
PISignals::setSlot(__sighandler__);
PISignals::grabSignals(PISignals::UserDefined1);
@@ -128,7 +124,7 @@ PIInit::PIInit() {
break;
}
}
# else
# else //WINDOWS
// OS version
DWORD dwVersion = GetVersion();
DWORD dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
@@ -154,26 +150,30 @@ PIInit::PIInit() {
setTimerResolutionAddr = (PINtSetTimerResolution)GetProcAddress(PRIVATE->ntlib, "NtSetTimerResolution");
__PISetTimerResolution();
}
# endif
# endif //WINDOWS
# ifdef HAS_LOCALE
//cout << "has locale" << endl;
//std::cout << "has locale" << std::endl;
if (currentLocale_t != 0) {
freelocale(currentLocale_t);
currentLocale_t = 0;
}
currentLocale_t = newlocale(LC_ALL, setlocale(LC_ALL, ""), 0);
# else
currentLocale_t = newlocale(LC_ALL, setlocale(LC_ALL, "C"), 0);
setlocale(LC_CTYPE, "en_US.UTF-8");
//std::ios_base::sync_with_stdio(false);
//std::locale utf8( std::locale(), new std::codecvt_utf8<wchar_t> );
//std::wcout.imbue(utf8);
# else //HAS_LOCALE
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
# endif
#else
# endif //HAS_LOCALE
#else //ANDROID
struct sigaction actions;
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = android_thread_exit_handler;
sigaction(SIGTERM, &actions, 0);
#endif
#endif //ANDROID
PRIVATE->delete_locs = false;
__syslocname__ = __sysoemname__ = 0;
__utf8name__ = const_cast<char*>("UTF-8");
@@ -201,20 +201,21 @@ PIInit::PIInit() {
# endif
//piCout << __syslocname__;
//piCout << __sysoemname__;
#else
#else //PIP_ICU
# ifdef WINDOWS
__syslocname__ = (char *)CP_ACP;
__sysoemname__ = (char *)CP_OEMCP;
__utf8name__ = (char *)CP_UTF8;
# endif
#endif
#endif //PIP_ICU
#ifdef MAC_OS
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &__pi_mac_clock);
#endif
char cbuff[1024];
memset(cbuff, 0, 1024);
if (gethostname(cbuff, 1023) == 0)
if (gethostname(cbuff, 1023) == 0) {
sinfo->hostname = cbuff;
}
#ifdef WINDOWS
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
@@ -236,7 +237,7 @@ PIInit::PIInit() {
ulong unlen = 1023;
if (GetUserName(cbuff, &unlen) != 0)
sinfo->user = cbuff;
#else
#else //WINDOWS
sinfo->processorsCount = piMaxi(1, int(sysconf(_SC_NPROCESSORS_ONLN)));
passwd * ps = getpwuid(getuid());
if (ps)
@@ -252,8 +253,8 @@ PIInit::PIInit() {
sinfo->OS_version = uns.release;
sinfo->architecture = uns.machine;
}
# endif
#endif
#endif //WINDOWS
#ifdef ESP_PLATFORM
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
@@ -275,6 +276,8 @@ PIInit::PIInit() {
PIStringAscii("FreeBSD");
#elif defined(FREERTOS)
PIStringAscii("FreeRTOS");
#elif defined(MICRO_PIP)
PIStringAscii("MicroPIP");
#else
uns.sysname;
#endif
@@ -305,49 +308,49 @@ PIInit::~PIInit() {
bool PIInit::isBuildOptionEnabled(PIInit::BuildOption o) {
switch (o) {
case ICU: return
case boICU: return
#ifdef PIP_ICU
true;
#else
false;
#endif
case USB: return
case boUSB: return
#ifdef PIP_USB
true;
#else
false;
#endif
case Crypt: return
case boCrypt: return
#ifdef PIP_CRYPT
true;
#else
false;
#endif
case Introspection: return
case boIntrospection: return
#ifdef PIP_INTROSPECTION
true;
#else
false;
#endif
case FFTW: return
case boFFTW: return
#ifdef PIP_FFTW
true;
#else
false;
#endif
case Compress: return
case boCompress: return
#ifdef PIP_COMPRESS
true;
#else
false;
#endif
case OpenCL: return
case boOpenCL: return
#ifdef PIP_OPENCL
true;
#else
false;
#endif
case Cloud: return
case boCloud: return
#ifdef PIP_CLOUD
true;
#else
@@ -361,14 +364,14 @@ bool PIInit::isBuildOptionEnabled(PIInit::BuildOption o) {
PIStringList PIInit::buildOptions() {
PIStringList ret;
if (isBuildOptionEnabled(ICU)) ret << "ICU";
if (isBuildOptionEnabled(USB)) ret << "USB";
if (isBuildOptionEnabled(Crypt)) ret << "Crypt";
if (isBuildOptionEnabled(Introspection)) ret << "Introspection";
if (isBuildOptionEnabled(FFTW)) ret << "FFTW";
if (isBuildOptionEnabled(Compress)) ret << "Compress";
if (isBuildOptionEnabled(OpenCL)) ret << "OpenCL";
if (isBuildOptionEnabled(Cloud)) ret << "Cloud";
if (isBuildOptionEnabled(boICU)) ret << "ICU";
if (isBuildOptionEnabled(boUSB)) ret << "USB";
if (isBuildOptionEnabled(boCrypt)) ret << "Crypt";
if (isBuildOptionEnabled(boIntrospection)) ret << "Introspection";
if (isBuildOptionEnabled(boFFTW)) ret << "FFTW";
if (isBuildOptionEnabled(boCompress)) ret << "Compress";
if (isBuildOptionEnabled(boOpenCL)) ret << "OpenCL";
if (isBuildOptionEnabled(boCloud)) ret << "Cloud";
return ret;
}
@@ -415,3 +418,6 @@ __PIInit_Initializer__::~__PIInit_Initializer__() {
__instance__ = 0;
}
}
#endif // MICRO_PIP

View File

@@ -1,5 +1,8 @@
/*! @file piinit.h
* @brief Initialization
/*! \file piinit.h
* \ingroup Core
* \~\brief
* \~english Library initialization
* \~russian Инициализация библиотеки
*/
/*
PIP - Platform Independent Primitives
@@ -23,6 +26,10 @@
#ifndef PIINIT_H
#define PIINIT_H
#include "pibase.h"
#ifndef MICRO_PIP
#include "piincludes.h"
@@ -47,19 +54,29 @@ class PIP_EXPORT PIInit {
public:
~PIInit();
//! @brief Build options which PIP library was built
//! \ingroup Core
//! \~english Build options which PIP library was built
//! \~russian Опции, с которыми был собран PIP
enum BuildOption {
ICU /*! Unicode support */ = 0x01,
USB /*! USB support */ = 0x02,
Crypt /*! Crypt support */ = 0x08,
Introspection /*! Introspection */ = 0x010,
FFTW /*! FFTW3 support */ = 0x40,
Compress /*! Zlib compression support */ = 0x80,
OpenCL /*! OpenCL support */ = 0x100,
Cloud /*! Cloud transport support */ = 0x200,
boICU /*! \~english Unicode support by ICU \~russian Поддержка юникода через ICU */ = 0x01,
boUSB /*! \~english USB support \~russian Поддержка USB */ = 0x02,
boCrypt /*! \~english Crypt support \~russian Поддержка шифрования */ = 0x08,
boIntrospection /*! \~english Introspection \~russian Интроспекция */ = 0x010,
boFFTW /*! \~english FFTW3 support \~russian Поддержка FFTW3 */ = 0x40,
boCompress /*! \~english Zlib compression support \~russian Поддержка сжатия Zlib */ = 0x80,
boOpenCL /*! \~english OpenCL support \~russian Поддержка OpenCL */ = 0x100,
boCloud /*! \~english PICloud transport support \~russian Поддержка облачного транспорта PICloud */ = 0x200,
};
static PIInit * instance() {return __PIInit_Initializer__::__instance__;}
//! \ingroup Core
//! \~english Returns if build option was enabled
//! \~russian Возвращает была ли включена опция при сборке
static bool isBuildOptionEnabled(BuildOption o);
//! \ingroup Core
//! \~english Returns build options as stringlist
//! \~russian Возвращает опции сборки как список строк
static PIStringList buildOptions();
private:
explicit PIInit();
@@ -70,4 +87,5 @@ private:
};
#endif // MICRO_PIP
#endif // PIINIT_H

View File

@@ -18,62 +18,172 @@
*/
#include "piobject.h"
#include "pisysteminfo.h"
#include "pithread.h"
#include "piconditionvar.h"
#ifndef FREERTOS
#ifndef MICRO_PIP
# include "pisysteminfo.h"
# include "pifile.h"
#endif
/** \class PIObject
* @brief This is base class for any classes which use events -> handlers mechanism.
* \details
* \section PIObject_sec0 Events and Event handlers
* %PIObject provide notification mechanism similar Qt but implemented
* on language capabilities without any special preprocessors or compilers.
* Any class inherits PIObject should use macro \a PIOBJECT() immediate
* after declaration to proper compile.
*
* Event is a some abstract event that can be raised at any time.
* Event is a function but declared with special macro \a EVENT().
* To raise event simply execute event function.
*
* Event handler is a function but declared with special macro
* \a EVENT_HANDLER(). You can use event handlers as ordinary functions.
*
* Main goal of this mechanism is perform abstract connections between
* various objects. This functionality provide macro \a CONNECT() which
* connect some event of first object to some event handler or event of
* second object. Each event can be connected any times to any event handlers.
*
* \image html events_handlers.png
*
* Example: \snippet piobject.cpp main
* Result:
\code{.cpp}
handler B: 2 , 0.5
handler A: event to handler
handler A: event to event
\endcode
*/
//! \addtogroup Core
//! \{
//! \~\class PIObject piobject.h
//! \~\brief
//! \~english This is base class for any classes which use events -> handlers mechanism
//! \~russian Этот класс является базовым для использования механизма события -> обработчики
//!
//! \~\details
//! \~english \section PIObject_sec0 Events and Event handlers
//! \~russian \section PIObject_sec0 События и Обработчики событий
//!
//! \~english
//! %PIObject provide notification mechanism similar Qt but implemented
//! on language capabilities without any special preprocessors or compilers.
//! Any class inherits %PIObject should use macro \a PIOBJECT() immediate
//! after declaration to proper compile.
//!
//! Event is a some abstract event that can be raised at any time as common method.
//! Event is a function but declared with special macro \a EVENT() and don`t need definition.
//! To raise event simply execute event function.
//!
//! Event handler is a function but declared with special macro
//! \a EVENT_HANDLER(). It need definition as common method.
//! You can use event handlers as ordinary functions.
//!
//! Main goal of this mechanism is perform abstract connections between
//! various objects. This functionality provide macro \a CONNECT(), \a CONNECTU() and \a CONNECTL() which
//! connect some event of first object to some event handler or event of
//! second object. Each event can be connected any times to any event handlers.
//!
//! * \a CONNECT() macros family work with explicit subclasses of %PIObject with compile-time check of events and handlers
//! * \a CONNECTU() macro can work implicit subclasses of %PIObject with run-time check of events and handlers
//! * \a CONNECTU_QUEUED() macro similar to \a CONNECTU() macro but queue execution with performer object instead of handler direct call
//! * \a CONNECTL() macro work with implicit subclasses of %PIObject and lambda-function
//!
//! \~russian
//! %PIObject предоставляет механизм событий и их обработчиков, реализованный без
//! дополнительного препроцессора или метакомпилятора. Любой класс, наследованный
//! от %PIObject должен использовать макрос \a PIOBJECT() сразу после объявления
//! класса для корректной работы.
//!
//! Событием является сигнал, который может быть вызван как обычный метод в любое время.
//! Это метод, объявленный с помощью макроса \a EVENT() и не требует описания.
//! Для его вызова просто вызывается метод события.
//!
//! Обработчик события это метод, объявленный с помощью макроса \a EVENT_HANDLER()
//! и он требует описания, как и обычный метод. Можно его использовать как обычный метод.
//!
//! Основной функцией этого механизма является реализация соединений между различными объектами.
//! Её предоставляют макросы \a CONNECT(), \a CONNECTU() и \a CONNECTL(), которые соединяют
//! события одних объектов с обработчиками или событиями других объектов. Каждое событие
//! может быть присоеденино неограниченное количество раз к любым обработчикам.
//!
//! * \a CONNECT() семейство макросов работает с явными наследниками %PIObject, и проверяет соединение во время компиляции
//! * \a CONNECTU() макрос может работать с неявными наследниками %PIObject, и проверяет соединение во время исполнения
//! * \a CONNECTU_QUEUED() макрос подобен \a CONNECTU(), но планирует вызов обработчика у объекта performer вместо прямого вызова
//! * \a CONNECTL() макрос может работать с неявными наследниками %PIObject и лямбда-функцией
//!
//! \~\image html events_handlers.png
//!
//! \~english Example:
//! \~russian Пример:
//!
//! \~\snippet piobject.cpp main
//! \~english Result:
//! \~russian Результат:
//! \~\code{.cpp}
//! handler B: 2 , 0.5
//! handler A: event to handler
//! handler A: event to event
//! event to lambda
//! \endcode
//! \}
//! \addtogroup Core
//! \{
//! \~\class PIObject::Connection piobject.h
//! \~\brief
//! \~english Helper class for obtain info about if connection successful and disconnect single connection
//! \~russian Вспомогательный класс для получения информации об успешности соединения и возможности его разрыва
//! \}
PIObject::__MetaFunc::__MetaFunc() {
for (int i = 0; i < __PIOBJECT_MAX_ARGS__; ++i) {
types[i] = names[i] = nullptr;
types_id[i] = 0;
}
}
int PIObject::__MetaFunc::argumentsCount() const {
for (int i = 0; i < __PIOBJECT_MAX_ARGS__; ++i)
if (!types[i])
return i;
return __PIOBJECT_MAX_ARGS__;
}
PIString PIObject::__MetaFunc::arguments() const {
return types.join(",");
PIString ret;
for (int i = 0; i < __PIOBJECT_MAX_ARGS__; ++i) {
if (!types[i]) break;
if (!ret.isEmpty()) ret += ',';
ret += PIStringAscii(types[i]);
}
return ret;
}
PIString PIObject::__MetaFunc::fullFormat() const {
PIString ret = type_ret + " " + scope + "::" + func_name +"(";
for (int i = 0; i < types.size_s(); ++i) {
PIString ret = PIStringAscii(type_ret) + " " +
PIStringAscii(scope) + "::" +
PIStringAscii(func_name) +"(";
for (int i = 0; i < __PIOBJECT_MAX_ARGS__; ++i) {
if (!types[i]) break;
if (i > 0) ret += ", ";
ret += types[i] + " " + names[i];
ret += PIStringAscii(types[i]) + " " + PIStringAscii(names[i]);
}
ret += ")";
return ret;
}
void PIObject::__MetaFunc::__setFuncName(const char * n) {
func_name = n;
func_name_id = PIStringAscii(n).hash();
}
void PIObject::__MetaFunc::__addArgument(const char * t, const char * n) {
for (int i = 0; i < __PIOBJECT_MAX_ARGS__; ++i) {
if (types[i]) continue;
types[i] = t;
names[i] = n;
types_id[i] = PIObject::simplifyType(t, false).hash();
break;
}
//PICout(PICoutManipulators::DefaultControls | PICoutManipulators::AddQuotes)
// << "__addArgument" << t << n << PIObject::simplifyType(t) << types_id.back();
}
bool PIObject::__MetaFunc::canConnectTo(const __MetaFunc & dst, int & args_count) const {
for (int i = 0; i < __PIOBJECT_MAX_ARGS__; ++i) {
//piCout << "canConnectTo" << i << types[i] << dst.types[i];
args_count = i;
if (!dst.types[i]) break;
if (!types[i]) return false;
if (types_id[i] != dst.types_id[i])
return false;
}
return true;
}
PIObject::PIObject(const PIString & name): _signature_(__PIOBJECT_SIGNATURE__), emitter_(0), thread_safe_(false), proc_event_queue(false) {
in_event_cnt = 0;
setName(name);
@@ -91,17 +201,10 @@ PIObject::~PIObject() {
mutexObjects().lock();
objects().removeAll(this);
mutexObjects().unlock();
piDisconnect(this);
deleted(this);
piDisconnectAll();
}
PIMap<PIString, PIVariant> PIObject::properties() const {
PIMap<PIString, PIVariant> ret;
piForeachC (PropertyHash p, properties_)
ret[p.second.first] = p.second.second;
return ret;
}
@@ -141,53 +244,14 @@ bool PIObject::executeQueued(PIObject * performer, const PIString & method, cons
}
void PIObject::piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h) {
PIObject * o = findByName(src);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
PIMutexLocker _ml(o->mutex_connect);
PIMutexLocker _mld(((PIObject*)dest)->mutex_connect, ((PIObject*)dest) != o);
o->connections << __Connection(ev_h, 0, sig, (PIObject*)dest, dest);
((PIObject*)dest)->connectors << o;
}
void PIObject::piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * o = findByName(dest);
if (o == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(o->mutex_connect, src != o);
src->connections << __Connection(ev_h, 0, sig, o, o);
((PIObject*)o)->connectors << src;
}
void PIObject::piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h) {
PIObject * s = findByName(src);
if (s == 0) {
piCout << "[PIObject] Can`t find object with name \"" << src << "\"!";
return;
}
PIObject * d = findByName(dest);
if (d == 0) {
piCout << "[PIObject] Can`t find object with name \"" << dest << "\"!";
return;
}
PIMutexLocker _ml(s->mutex_connect);
PIMutexLocker _mld(d->mutex_connect, s != d);
s->connections << __Connection(ev_h, 0, sig, d, d);
d->connectors << s;
}
PIStringList PIObject::scopeList() const {
PIStringList ret;
ret.reserve(2);
PIMutexLocker ml(__meta_mutex());
return __meta_data()[classNameID()].scope_list;
const PIVector<const char *> & scope(__meta_data()[classNameID()].scope_list);
for (const char * c: scope)
ret << PIStringAscii(c);
return ret;
}
@@ -202,10 +266,11 @@ PIStringList PIObject::methodsEH() const {
bool PIObject::isMethodEHContains(const PIString & name) const {
uint search_id = name.hash();
PIMutexLocker ml(__meta_mutex());
const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) {
if (eh.value().func_name == name)
if (eh.value().func_name_id == search_id)
return true;
}
return false;
@@ -213,10 +278,11 @@ bool PIObject::isMethodEHContains(const PIString & name) const {
PIString PIObject::methodEHArguments(const PIString & name) const {
uint search_id = name.hash();
PIMutexLocker ml(__meta_mutex());
const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) {
if (eh.value().func_name == name)
if (eh.value().func_name_id == search_id)
return eh.value().arguments();
}
return PIString();
@@ -224,10 +290,11 @@ PIString PIObject::methodEHArguments(const PIString & name) const {
PIString PIObject::methodEHFullFormat(const PIString & name) const {
uint search_id = name.hash();
PIMutexLocker ml(__meta_mutex());
const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) {
if (eh.value().func_name == name)
if (eh.value().func_name_id == search_id)
return eh.value().fullFormat();
}
return PIString();
@@ -240,10 +307,11 @@ PIString PIObject::methodEHFromAddr(const void * addr) const {
PIVector<PIObject::__MetaFunc> PIObject::findEH(const PIString & name) const {
uint search_id = name.hash();
PIVector<__MetaFunc> ret;
const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) {
if (eh.value().func_name == name)
if (eh.value().func_name_id == search_id)
ret << eh.value();
}
return ret;
@@ -256,31 +324,33 @@ PIObject::__MetaFunc PIObject::methodEH(const void * addr) const {
}
void PIObject::piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc) {
PIObject::Connection PIObject::piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc) {
//piCout << "piConnect ...";
//piCout << "piConnect" << src << (void*)(dest) << sig;
//piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className();
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest_o->mutex_connect, src != dest_o);
src->connections << __Connection(ev_h, e_h, sig, dest_o, dest, args);
Connection conn(ev_h, e_h, sig, src, dest_o, dest, args);
src->connections << conn;
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s() << "...";
//piCout << "addConnector" << dest_o << src;
dest_o->connectors << src;
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s();
//piCout << "piConnect ok";
return conn;
}
bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer) {
if (src == 0 || dest_o == 0 || dest == 0) return false;
PIObject::Connection PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer) {
if (src == 0 || dest_o == 0 || dest == 0) return Connection();
if (!src->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")";
return false;
return Connection();
}
if (!dest_o->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")";
return false;
return Connection();
}
PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect);
@@ -288,11 +358,11 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_
PIVector<__MetaFunc> m_src = src->findEH(sig), m_dest = dest_o->findEH(hname);
if (m_src.isEmpty()) {
piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
return false;
return Connection();
}
if (m_dest.isEmpty()) {
piCout << "[piConnectU] Error: can`t find handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
return false;
return Connection();
}
void * addr_src(0), * addr_dest(0);
int args(0);
@@ -301,35 +371,35 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_
if (addr_src != 0) break;
piForeachC (__MetaFunc & fd, m_dest) {
if (addr_src != 0) break;
if (fs.arguments().startsWith(fd.arguments()) || fd.arguments().isEmpty()) {
if (fs.canConnectTo(fd, args)) {
addr_src = fs.addr;
addr_dest = que ? fd.addrV : fd.addr;
args = fd.names.size_s();
}
}
}
if (addr_src == 0) {
piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className()
<< "\" and handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")";
return false;
return Connection();
}
src->connections << PIObject::__Connection(addr_dest, addr_src, sig, dest_o, dest, args, performer);
Connection conn(addr_dest, addr_src, sig, src, dest_o, dest, args, performer);
src->connections << conn;
if (que) performer->proc_event_queue = true;
dest_o->connectors << src;
//piCout << cc << cq << _ol.size();//"connect" << src << "->" << dest_o << ", dest.connectors.size() =" << dest_o->connectors.size();
return true;
return conn;
}
bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc) {
PIObject::Connection PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc) {
if (src == 0) {
delete f;
return false;
return Connection();
}
if (!src->isPIObject()) {
piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")";
delete f;
return false;
return Connection();
}
PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect);
@@ -338,19 +408,19 @@ bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<v
if (m_src.isEmpty()) {
piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f;
return false;
return Connection();
}
if (m_src.size() != 1) {
piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f;
return false;
return Connection();
}
PIObject::__Connection conn(0, m_src[0].addr, sig);
PIObject::Connection conn(0, m_src[0].addr, sig, src);
//piCout << "found";
conn.functor = f;
src->connections << conn;
//piCout << "finished";
return true;
return conn;
}
@@ -358,7 +428,7 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]);
Connection & cc(src->connections[i]);
if (cc.event == sig && cc.dest_o == dest && cc.slot == ev_h) {
src->connections[i].destroy();
src->connections.remove(i);
@@ -373,7 +443,7 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]);
Connection & cc(src->connections[i]);
if (cc.event == sig && cc.dest_o == dest) {
src->connections[i].destroy();
src->connections.remove(i);
@@ -387,14 +457,14 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
PIMutexLocker _ml(src->mutex_connect);
for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]);
Connection & cc(src->connections[i]);
if (cc.event == sig) {
PIObject * dest = cc.dest_o;
if (!dest) {
src->connections[i].destroy();
src->connections.remove(i);
i--;
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
src->connections[i].destroy();
src->connections.remove(i);
i--;
if (dest) {
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(MICRO_PIP)
PIMutexLocker _mld(dest->mutex_connect, src != dest);
#endif
dest->updateConnectors();
@@ -404,37 +474,38 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
}
void PIObject::piDisconnect(PIObject * src) {
src->deleted(src);
PIMutexLocker _ml(src->mutex_connect);
PIVector<PIObject * > cv = src->connectors.toVector();
void PIObject::piDisconnectAll() {
PIMutexLocker _ml(mutex_connect);
PIVector<PIObject * > cv = connectors.toVector();
// piCout << "disconnect connectors =" << connectors.size();
piForeach (PIObject * o, cv) {
//piCout << "disconnect"<< src->className()<< o->className();
if (!o || (o == src)) continue;
// piCout << "disconnect"<< src << o;
if (!o || (o == this)) continue;
if (!o->isPIObject()) continue;
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS)
PIMutexLocker _mld(o->mutex_connect, src != o);
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(MICRO_PIP)
PIMutexLocker _mld(o->mutex_connect, this != o);
#endif
PIVector<__Connection> & oc(o->connections);
PIVector<Connection> & oc(o->connections);
for (int i = 0; i < oc.size_s(); ++i) {
if (oc[i].functor) continue;
//piCout << " check" << (void*)(oc[i].dest_o) << "==" << (void*)(src);
if (oc[i].dest_o == src) {
if (oc[i].dest_o == this) {
oc[i].destroy();
oc.remove(i);
--i;
}
}
}
piForeachC (PIObject::__Connection & c, src->connections) {
// piCout << "disconnect connections =" << connections.size();
piForeachC (PIObject::Connection & c, connections) {
if (c.functor) continue;
if (!c.dest_o) continue;
if (!c.dest_o->isPIObject()) continue;
c.dest_o->connectors.remove(src);
c.dest_o->connectors.remove(this);
}
for (int i = 0; i < src->connections.size_s(); ++i)
src->connections[i].destroy();
src->connections.clear();
for (int i = 0; i < connections.size_s(); ++i)
connections[i].destroy();
connections.clear();
}
@@ -444,8 +515,8 @@ void PIObject::updateConnectors() {
PIMutexLocker _ml(mutexObjects());
piForeach (PIObject * o, objects()) {
if (o == this) continue;
PIVector<__Connection> & oc(o->connections);
piForeach (__Connection & c, oc)
PIVector<Connection> & oc(o->connections);
piForeach (Connection & c, oc)
if (c.dest == this)
connectors << o;
}
@@ -492,6 +563,14 @@ void PIObject::callQueuedEvents() {
}
//! \details
//! \~english
//! On first call background thread started to delete objects.
//! Each object deletes when it`s outside from any events and hadlers.
//! \~russian
//! При первом вызове стартует фоновый поток для удаления объектов.
//! Каждый объект из очереди удаляется только когда выйдет из всех
//! событий и обработок.
void PIObject::deleteLater() {
Deleter::instance()->post(this);
}
@@ -506,7 +585,7 @@ bool PIObject::findSuitableMethodV(const PIString & method, int args, int & ret_
int mfi = -1, ac = -1, mac = -1;
for (int i = 0; i < ml.size_s(); ++i) {
__MetaFunc & m(ml[i]);
int j = m.names.size_s();
int j = m.argumentsCount();
if (mac < 0 || mac > j) mac = j;
if ((j <= args) && (ac < j)) {
ac = j;
@@ -548,30 +627,46 @@ void PIObject::callAddrV(void * slot, void * obj, int args, const PIVector<PIVar
}
PIString PIObject::simplifyType(const char * a) {
PIString PIObject::simplifyType(const char * a, bool readable) {
PIString ret = PIStringAscii(a).trim();
int white = -1;
for (int i = 0; i < ret.size_s(); ++i) {
bool iw = ret[i] == ' ' || ret[i] == '\t' || ret[i] == '\r' || ret[i] == '\n';
//piCout << i << iw << white;
if (white < 0) {
if (iw) {
white = i;
continue;
}
} else {
if (!iw) {
ret.replace(white, i - white, " ");
i = white;
white = -1;
//piCout << i;
if (readable) {
int white = -1;
for (int i = 0; i < ret.size_s(); ++i) {
bool iw = ret[i] == ' ' || ret[i] == '\t' || ret[i] == '\r' || ret[i] == '\n';
//piCout << i << iw << white;
if (white < 0) {
if (iw) {
white = i;
continue;
}
} else {
if (!iw) {
ret.replace(white, i - white, " ");
i = white;
white = -1;
//piCout << i;
}
}
}
ret.replaceAll(" [", '[');
ret.replaceAll(" ]", ']');
ret.replaceAll(" <", '<');
ret.replaceAll(" >", '>');
ret.replaceAll(" &", '&');
ret.replaceAll(" *", '*');
ret.replaceAll("[ ", '[');
ret.replaceAll("] ", ']');
ret.replaceAll("< ", '<');
ret.replaceAll("> ", '>');
ret.replaceAll("& ", '&');
ret.replaceAll("* ", '*');
if (ret.startsWith("const ") && ret.endsWith("&"))
ret.cutLeft(6).cutRight(1).trim();
} else {
if (ret.startsWith("const ") && ret.endsWith("&"))
ret.cutLeft(6).cutRight(1).trim();
ret.removeAll(' ').removeAll('\t').removeAll('\r').removeAll('\n');
}
ret.replaceAll(" &", "&");
ret.replaceAll(" *", "*");
if (ret.startsWith("const ") && ret.endsWith("&"))
ret.cutLeft(6).cutRight(1).trim();
return ret;
}
@@ -589,9 +684,12 @@ void PIObject::dump(const PIString & line_prefix) const {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " properties {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << properties_.size_s();
//printf("dump %d properties\n", properties_.size());
piForeachC (PropertyHash p, properties_)
if (p.first != PIString("name").hash())
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << p.second.first << ": " << p.second.second;
const char * o_name = "name";
auto it = properties_.makeIterator();
while (it.next()) {
if (it.key() != piHashData((const uchar *)o_name, strlen(o_name)))
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << it.key() << ": " << it.value();
}
//printf("dump %d properties ok\n", properties_.size());
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " methods {";
@@ -606,17 +704,18 @@ void PIObject::dump(const PIString & line_prefix) const {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " connections {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << connections.size_s();
//printf("dump %d connections\n",connections.size());
piForeachC (__Connection & c, connections) {
for (const Connection & c : connections) {
PIObject * dst = c.dest_o;
__MetaFunc ef = methodEH(c.signal);
PIString src(c.event);
if (!ef.func_name.isEmpty())
src = ef.func_name + "(" + ef.arguments() + ")";
if (ef.func_name)
src = PIStringAscii(ef.func_name) + "(" + ef.arguments() + ")";
if (dst) {
__MetaFunc hf = dst->methodEH(c.slot);
if (hf.func_name.isEmpty()) hf.func_name = "[BROKEN]";
else hf.func_name += "(" + hf.arguments() + ")";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << dst->className() << " (" << c.dest << ", \"" << dst->name() << "\")::" << hf.func_name;
PIString hf_fn;
if (!hf.func_name) hf_fn = "[BROKEN]";
else hf_fn = PIStringAscii(hf.func_name) + "(" + hf.arguments() + ")";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << dst->className() << " (" << c.dest << ", \"" << dst->name() << "\")::" << hf_fn;
} else {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << "[lambda]";
}
@@ -627,7 +726,8 @@ void PIObject::dump(const PIString & line_prefix) const {
}
void dumpApplication() {
#ifndef MICRO_PIP
void dumpApplication(bool with_objects) {
PIMutexLocker _ml(PIObject::mutexObjects());
//printf("dump application ...\n");
PIDateTime cd = PIDateTime::current();
@@ -645,23 +745,24 @@ void dumpApplication() {
PICout(PICoutManipulators::AddNewLine) << " uptime: " << PITime::fromSystemTime(cd.toSystemTime() - pi->execDateTime.toSystemTime()).toString();
PICout(PICoutManipulators::AddNewLine) << " PIObjects {";
PICout(PICoutManipulators::AddNewLine) << " count: " << PIObject::objects().size_s();
piForeachC (PIObject * o, PIObject::objects())
o->dump(" ");
if (with_objects) {
for (const PIObject * o: PIObject::objects())
o->dump(" ");
}
PICout(PICoutManipulators::AddNewLine) << " }";
PICout(PICoutManipulators::AddNewLine) << "}";
//printf("dump application done\n");
}
#ifndef FREERTOS
bool dumpApplicationToFile(const PIString & path) {
bool dumpApplicationToFile(const PIString & path, bool with_objects) {
PIFile f(path + "_tmp");
f.setName("__S__DumpFile");
f.clear();
if (!f.open(PIIODevice::WriteOnly)) return false;
bool ba = PICout::isBufferActive();
PICout::setBufferActive(true, true);
dumpApplication();
dumpApplication(with_objects);
f << PICout::buffer();
f.close();
PICout::setBufferActive(ba, true);
@@ -671,7 +772,7 @@ bool dumpApplicationToFile(const PIString & path) {
#endif
void PIObject::__MetaData::addScope(const PIString & s, uint shash) {
void PIObject::__MetaData::addScope(const char * s, uint shash) {
if (!scope_id.contains(shash)) {
scope_list << s;
scope_id << shash;
@@ -679,41 +780,87 @@ void PIObject::__MetaData::addScope(const PIString & s, uint shash) {
}
void PIObject::__Connection::destroy() {
void PIObject::Connection::destroy() {
if (functor) delete functor;
functor = nullptr;
}
PIObject::Connection::Connection() {
slot = signal = dest = nullptr;
src_o = dest_o = performer = nullptr;
functor = nullptr;
eventID = 0;
args_count = 0;
}
bool PIObject::Connection::disconnect() {
if (!isValid() || !src_o) return false;
if (!src_o->isPIObject()) return false;
bool ndm = dest_o && (src_o != dest_o), ret = false, found = false;
if (dest_o) {
if (!dest_o->isPIObject()) ndm = false;
}
PIMutexLocker _ml(src_o->mutex_connect);
if (ndm) dest_o->mutex_connect.lock();
for (int i = 0; i < src_o->connections.size_s(); ++i) {
Connection & cc(src_o->connections[i]);
if (cc.eventID == eventID) {
if (dest_o && (cc.dest_o == dest_o)) {
if (cc.slot == slot)
found = true;
}
if (functor && (cc.functor == functor))
found = true;
}
if (found) {
src_o->connections[i].destroy();
src_o->connections.remove(i);
ret = true;
break;
}
}
if (dest_o) {
if (dest_o->isPIObject())
dest_o->updateConnectors();
}
if (ndm) dest_o->mutex_connect.unlock();
return ret;
}
PRIVATE_DEFINITION_START(PIObject::Deleter)
PIThread thread;
PIConditionVariable cond_var;
PIMutex cond_mutex, queue_mutex;
PIVector<PIObject*> obj_queue;
PRIVATE_DEFINITION_END(PIObject::Deleter)
PIObject::Deleter::Deleter() {
//piCout << "Deleter start ...";
stopping = started = posted = false;
CONNECTL(&(PRIVATE->thread), started, [this](){proc();});
PRIVATE->thread.startOnce();
while (!started)
piMSleep(1);
PRIVATE->thread.setSlot([this](){
PIVector<PIObject*> oq;
PRIVATE->thread.lock();
while(PRIVATE->obj_queue.isEmpty()) PRIVATE->cond_var.wait(PRIVATE->thread.mutex());
oq.swap(PRIVATE->obj_queue);
PRIVATE->thread.unlock();
for (PIObject * o : oq) deleteObject(o);
});
PRIVATE->thread.start();
}
PIObject::Deleter::~Deleter() {
//piCout << "~Deleter ...";
stopping = true;
PRIVATE->thread.stop();
PRIVATE->cond_var.notifyAll();
#ifndef WINDOWS
while (PRIVATE->thread.isRunning())
piMSleep(1);
#endif
deleteAll();
PRIVATE->thread.waitForFinish();
for (PIObject * o : PRIVATE->obj_queue) deleteObject(o);
//piCout << "~Deleter ok";
}
@@ -727,46 +874,13 @@ PIObject::Deleter * PIObject::Deleter::instance() {
void PIObject::Deleter::post(PIObject * o) {
if (!o->isPIObject()) return;
//piCout << "[Deleter] post" << o << "...";
PRIVATE->queue_mutex.lock();
if (!PRIVATE->obj_queue.contains(o))
PRIVATE->thread.lock();
if (!PRIVATE->obj_queue.contains(o)) {
PRIVATE->obj_queue << o;
PRIVATE->queue_mutex.unlock();
PRIVATE->cond_var.notifyAll();
posted = true;
//piCout << "[Deleter] post" << o << "done";
}
void PIObject::Deleter::proc() {
//piCout << "[Deleter] proc start";
while (!stopping) {
//piMSleep(1);
//piCout << "[Deleter] proc wait ...";
if (posted) {
posted = false;
started = true;
} else {
PRIVATE->cond_mutex.lock();
started = true;
PRIVATE->cond_var.wait(PRIVATE->cond_mutex);
PRIVATE->cond_mutex.unlock();
}
//piCout << "[Deleter] proc wait done";
deleteAll();
PRIVATE->cond_var.notifyAll();
}
//piCout << "[Deleter] proc end ok";
}
void PIObject::Deleter::deleteAll() {
PIVector<PIObject*> oq;
PRIVATE->queue_mutex.lock();
oq = PRIVATE->obj_queue;
//piCout << "[Deleter] deleteAll" << oq.size_s() << "...";
PRIVATE->obj_queue.clear();
PRIVATE->queue_mutex.unlock();
piForeach (PIObject * o, oq)
deleteObject(o);
PRIVATE->thread.unlock();
//piCout << "[Deleter] post" << o << "done";
}
@@ -774,12 +888,9 @@ void PIObject::Deleter::deleteObject(PIObject * o) {
//piCout << "[Deleter] delete" << (uintptr_t)o << "...";
if (o->isPIObject()) {
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ...";
while (o->isInEvent()) {
piMSleep(1);
}
while (o->isInEvent()) piMinSleep();
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done";
if (o->isPIObject())
delete o;
delete o;
}
//piCout << "[Deleter] delete" << (uintptr_t)o << "done";
}

View File

@@ -1,7 +1,8 @@
/*! @file piobject.h
* @brief Base object
*
* This file declare PIObject class
/*! \file piobject.h
* \ingroup Core
* \~\brief
* \~english Base object
* \~russian Базовый класс
*/
/*
PIP - Platform Independent Primitives
@@ -33,71 +34,125 @@
#include "piqueue.h"
#include "piobject_macros.h"
typedef void (*Handler)(void * );
class PIP_EXPORT PIObject {
#ifndef MICRO_PIP
friend class PIObjectManager;
friend void dumpApplication();
friend void dumpApplication(bool);
friend class PIIntrospection;
#endif
typedef PIObject __PIObject__;
typedef void __Parent__;
friend class PIIntrospection;
public:
NO_COPY_CLASS(PIObject)
//! Contructs PIObject with name "name"
//! \~english Contructs %PIObject with name "name"
//! \~russian Создает %PIObject с именем "name"
explicit PIObject(const PIString & name = PIString());
virtual ~PIObject();
class PIP_EXPORT Connection {
friend class PIObject;
Connection(void * sl, void * si, const PIString & e = PIString(),
PIObject * s_o = nullptr, PIObject * d_o = nullptr,
void * d = nullptr, int ac = 0, PIObject * p = nullptr) {
slot = sl;
signal = si;
event = e;
eventID = e.hash();
src_o = s_o;
dest_o = d_o;
dest = d;
args_count = ac;
performer = p;
functor = 0;
}
void destroy();
void * slot;
void * signal;
std::function<void()> * functor;
PIString event;
uint eventID;
PIObject * src_o, * dest_o;
PIObject * performer;
void * dest;
int args_count;
public:
//! \~english Contructs invalid %Connection
//! \~russian Создает недействительный %Connection
Connection();
//! \~english Returns if %Connection is valid
//! \~russian Возвращает успешен ли %Connection
bool isValid() const {return signal;}
//! \~english Returns source object
//! \~russian Возвращает объект-источник
PIObject * sourceObject() const {return src_o;}
//! \~english Returns destination object or "nullptr" if this is lambda connection
//! \~russian Возвращает объект-приемник или "nullptr" если это соединение на лямбда-функцию
PIObject * destinationObject() const {return dest_o;}
//! \~english Returns performer object or "nullptr" if this is non-queued connection
//! \~russian Возвращает объект-исполнитель или "nullptr" если это соединение не отложенное
PIObject * performerObject() const {return performer;}
//! \~english Disconnect this %Connection, returns if operation successful
//! \~russian Разрывает этот %Connection, возвращает успешен ли разрыв
bool disconnect();
};
private:
uint _signature_;
public:
//! Returns object name
PIString name() const {return property(PIStringAscii("name")).toString();}
//! \~english Returns object name
//! \~russian Возвращает имя объекта
PIString name() const {return property("name").toString();}
//! Returns object class name
//! \~english Returns object class name
//! \~russian Возвращает имя класса объекта
virtual const char * className() const {return "PIObject";}
virtual uint classNameID() const {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
static const PIString __classNameS() {return PIStringAscii("PIObject");}
static const char * __classNameCC() {return "PIObject";}
static uint __classNameIDS() {static uint ret = PIStringAscii("PIObject").hash(); return ret;}
//! Returns parent object class name
//! \~english Returns parent class name
//! \~russian Возвращает имя родительского класса
virtual const char * parentClassName() const {return "";}
//! Return if debug of this object is active
bool debug() const {return property(PIStringAscii("debug")).toBool();}
//! \~english Return if \a piCoutObj of this object is active
//! \~russian Возвращает включен ли вывод \a piCoutObj для этого объекта
bool debug() const {return property("debug").toBool();}
//! Set object name
void setName(const PIString & name) {setProperty(PIStringAscii("name"), name);}
void setName(const char * name) {setName(PIStringAscii(name));}
//! \~english Set object name
//! \~russian Устанавливает имя объекта
void setName(const PIString & name) {setProperty("name", name);}
//! \~english Set object \a piCoutObj active
//! \~russian Включает или отключает вывод \a piCoutObj для этого объекта
void setDebug(bool debug) {setProperty("debug", debug);}
//! Set object debug active
void setDebug(bool debug) {setProperty(PIStringAscii("debug"), debug);}
//! \~english Returns property with name "name"
//! \~russian Возвращает свойство объекта по имени "name"
PIVariant property(const char * name) const {return properties_.value(piHashData((const uchar *)name, strlen(name)));}
//! Returns properties of the object
PIMap<PIString, PIVariant> properties() const;
//! \~english Set property with name "name" to "value". If there is no such property in object it will be added
//! \~russian Устанавливает у объекта свойство по имени "name" в "value". Если такого свойства нет, оно добавляется
void setProperty(const char * name, const PIVariant & value) {properties_[piHashData((const uchar *)name, strlen(name))] = value; propertyChanged(name);}
//! Returns properties count of the object
int propertiesCount() const {return properties_.size_s();}
//! Returns property with name "name"
PIVariant property(const PIString & name) const {return properties_.value(name.hash(), Property(PIString(), PIVariant())).second;}
PIVariant property(const char * name) const {return property(PIStringAscii(name));}
//! Set property with name "name" to "value". If there is no such property in object it will be added
void setProperty(const PIString & name, const PIVariant & value) {properties_[name.hash()] = Property(name, value); propertyChanged(name);}
void setProperty(const char * name, const PIVariant & value) {setProperty(PIStringAscii(name), value);}
//! Returns if property with name "name" exists
bool isPropertyExists(const PIString & name) const {return properties_.contains(name.hash());}
bool isPropertyExists(const char * name) const {return isPropertyExists(PIStringAscii(name));}
//! \~english Returns if property with name "name" exists
//! \~russian Возвращает присутствует ли свойство по имени "name"
bool isPropertyExists(const char * name) const {return properties_.contains(piHashData((const uchar *)name, strlen(name)));}
void setThreadSafe(bool yes) {thread_safe_ = yes;}
bool isThreadSafe() const {return thread_safe_;}
@@ -133,7 +188,10 @@ public:
void dump(const PIString & line_prefix = PIString()) const;
//! \~english Returns subclass scope of this object (including this class name)
//! \~russian Возвращает цепочку наследования объекта (вместе с классом самого объекта)
PIStringList scopeList() const;
PIStringList methodsEH() const;
bool isMethodEHContains(const PIString & name) const;
PIString methodEHArguments(const PIString & name) const;
@@ -141,33 +199,44 @@ public:
PIString methodEHFromAddr(const void * addr) const;
// / Direct connect
static void piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc);
static bool piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0);
static bool piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc);
template <typename INPUT, typename... TYPES>
static std::function<void()> * __newFunctor(void(*stat_handler)(void*,TYPES...), INPUT functor) {
return (std::function<void()>*)(new std::function<void(TYPES...)>(functor));
static PIObject::Connection piConnect(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, void * ev_h, void * e_h, int args, const char * loc);
static PIObject::Connection piConnectU(PIObject * src, const PIString & sig, PIObject * dest_o, void * dest, const PIString & hname, const char * loc, PIObject * performer = 0);
static PIObject::Connection piConnectLS(PIObject * src, const PIString & sig, std::function<void()> * f, const char * loc);
template <typename PIINPUT, typename... PITYPES>
static std::function<void()> * __newFunctor(void(*stat_handler)(void*,PITYPES...), PIINPUT functor) {
return (std::function<void()>*)(new std::function<void(PITYPES...)>(functor));
}
// / Through names and mixed
static void piConnect(const PIString & src, const PIString & sig, void * dest, void * ev_h);
static void piConnect(PIObject * src, const PIString & sig, const PIString & dest, void * ev_h);
static void piConnect(const PIString & src, const PIString & sig, const PIString & dest, void * ev_h);
//! \~english Disconnect object from all connections with event name "sig", connected to destination object "dest" and handler "ev_h"
//! \~russian Разрывает все соединения от события "sig" к объекту "dest" и обработчику "ev_h"
void piDisconnect(const PIString & sig, PIObject * dest, void * ev_h) {piDisconnect(this, sig, dest, ev_h);}
//! \~english Disconnect object from all connections with event name "sig", connected to destination object "dest"
//! \~russian Разрывает все соединения от события "sig" к объекту "dest"
void piDisconnect(const PIString & sig, PIObject * dest) {piDisconnect(this, sig, dest);}
//! \~english Disconnect object from all connections with event name "sig"
//! \~russian Разрывает все соединения от события "sig"
void piDisconnect(const PIString & sig) {piDisconnect(this, sig);}
//! \~english Disconnect object "src" from all connections with event name "sig", connected to destination object "dest" and handler "ev_h"
//! \~russian Разрывает все соединения от события "sig" объекта "src" к объекту "dest" и обработчику "ev_h"
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest, void * ev_h);
//! \~english Disconnect object "src" from all connections with event name "sig", connected to destination object "dest"
//! \~russian Разрывает все соединения от события "sig" объекта "src" к объекту "dest"
static void piDisconnect(PIObject * src, const PIString & sig, PIObject * dest);
//! Disconnect object "src" from all connections with event name "sig"
//! \~english Disconnect object "src" from all connections with event name "sig"
//! \~russian Разрывает все соединения от события "sig" объекта "src"
static void piDisconnect(PIObject * src, const PIString & sig);
//! Disconnect object "src" from all connections, i.e. all connections where object "src" is emitter
static void piDisconnect(PIObject * src);
// / Raise events
static void raiseEvent(PIObject * sender, const uint eventID) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
if (i.functor) {
(*(i.functor))();
@@ -196,7 +265,7 @@ public:
template <typename T0>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
if (i.functor) {
(*((std::function<void(T0)>*)i.functor))(v0);
@@ -227,7 +296,7 @@ public:
template <typename T0, typename T1>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
if (i.functor) {
(*((std::function<void(T0, T1)>*)i.functor))(v0, v1);
@@ -262,7 +331,7 @@ public:
template <typename T0, typename T1, typename T2>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
if (i.functor) {
(*((std::function<void(T0, T1, T2)>*)i.functor))(v0, v1, v2);
@@ -299,7 +368,7 @@ public:
template <typename T0, typename T1, typename T2, typename T3>
static void raiseEvent(PIObject * sender, const uint eventID, const T0 & v0 = T0(), const T1 & v1 = T1(), const T2 & v2 = T2(), const T3 & v3 = T3()) {
for (int j = 0; j < sender->connections.size_s(); ++j) {
__Connection i(sender->connections[j]);
Connection i(sender->connections[j]);
if (i.eventID != eventID) continue;
if (i.functor) {
(*((std::function<void(T0, T1, T2, T3)>*)i.functor))(v0, v1, v2, v3);
@@ -343,64 +412,89 @@ public:
if (i->name() != name) continue;
return i;
}
return 0;
return nullptr;
}
//! \~english Returns if this is valid %PIObject (check signature)
//! \~russian Возвращает действительный ли это %PIObject (проверяет подпись)
bool isPIObject() const {return isPIObject(this);}
//! \~english Returns if this is valid %PIObject subclass "T" (check signature and classname)
//! \~russian Возвращает действительный ли это наследник %PIObject типа "T" (проверяет подпись и имя класса)
template<typename T>
bool isTypeOf() const {
if (!isPIObject()) return false;
return scopeList().contains(T::__classNameS());
PIMutexLocker ml(__meta_mutex());
return __meta_data()[classNameID()].scope_id.contains(T::__classNameIDS());
}
//! \~english Returns cast to T if this is valid subclass "T" (check by \a isTypeOf()) or "nullptr"
//! \~russian Возвращает преобразование к типу T если это действительный наследник типа "T" (проверяет через \a isTypeOf()), или "nullptr"
template<typename T>
T * cast() const {
if (!isTypeOf<T>()) return (T*)0;
if (!isTypeOf<T>()) return (T*)nullptr;
return (T*)this;
}
//! \~english Returns if "o" is valid %PIObject (check signature)
//! \~russian Возвращает действительный ли "o" %PIObject (проверяет подпись)
static bool isPIObject(const PIObject * o);
static bool isPIObject(const void * o) {return isPIObject((PIObject*)o);}
//! \~english Returns if "o" is valid %PIObject subclass "T" (check signature and classname)
//! \~russian Возвращает действительный ли "o" наследник %PIObject типа "T" (проверяет подпись и имя класса)
template<typename T>
static bool isTypeOf(const PIObject * o) {return o->isTypeOf<T>();}
template<typename T>
static bool isTypeOf(const void * o) {return isTypeOf<T>((PIObject*)o);}
static PIString simplifyType(const char * a);
static PIString simplifyType(const char * a, bool readable = true);
struct PIP_EXPORT __MetaFunc {
__MetaFunc(): addr(0), addrV(0) {;}
bool isNull() const {return addr == 0;}
__MetaFunc();
bool isNull() const {return addr == nullptr;}
int argumentsCount() const;
PIString arguments() const;
PIString fullFormat() const;
void * addr;
void * addrV;
PIString func_name;
PIString type_ret;
PIString scope;
PIStringList types;
PIStringList names;
void __setFuncName(const char * n);
void __addArgument(const char * t, const char * n);
bool canConnectTo(const __MetaFunc & dst, int & args_count) const;
void * addr = nullptr;
void * addrV = nullptr;
uint func_name_id = 0;
const char * func_name = nullptr;
const char * type_ret = nullptr;
const char * scope = nullptr;
const char * types[__PIOBJECT_MAX_ARGS__];
const char * names[__PIOBJECT_MAX_ARGS__];
uint types_id[__PIOBJECT_MAX_ARGS__];
};
struct PIP_EXPORT __MetaData {
__MetaData() {scope_list << PIStringAscii("PIObject"); scope_id << PIStringAscii("PIObject").hash();}
void addScope(const PIString & s, uint shash);
PIStringList scope_list;
__MetaData() {scope_list << "PIObject"; scope_id << PIStringAscii("PIObject").hash();}
void addScope(const char * s, uint shash);
PIVector<const char *> scope_list;
PISet<uint> scope_id;
PISet<const void * > eh_set;
PIMap<const void * , __MetaFunc> eh_func;
};
typedef PIPair<const void * , __MetaFunc> __EHPair;
//! @brief Execute all posted events from CONNECTU_QUEUED connections
//! \~english Execute all posted events from CONNECTU_QUEUED connections
//! \~russian Выполнить все отложенные события от CONNECTU_QUEUED соединений
void callQueuedEvents();
//! @brief Check if any CONNECTU_QUEUED connections to this object and execute them
//! \~english
//! \brief Check if any CONNECTU_QUEUED connections to this object and execute them
//! \details This function is more optimized than \a callQueuedEvents() for objects that doesn`t
//! appears as \"performer\" target at CONNECTU_QUEUED
//! \~russian
//! \brief Если было хотя бы одно CONNECTU_QUEUED соединение с исполнителем this, то выполнить события
//! \details Этот метод более оптимален, чем \a callQueuedEvents(), для объектов, которые не были в роли
//! \"performer\" в макросе CONNECTU_QUEUED
bool maybeCallQueuedEvents() {if (proc_event_queue) callQueuedEvents(); return proc_event_queue;}
//! @brief Mark object to delete
//! \details On first call background thread started to delete objects.
//! Each object deletes when it`s outside from any events and hadlers.
//! \~english Mark object to delete
//! \~russian Пометить объект на удаление
void deleteLater();
static PIMutex & __meta_mutex();
@@ -408,50 +502,35 @@ public:
protected:
//! Returns PIObject* which has raised an event. This value is correct only in definition of some event handler
//! \~english Returns %PIObject* which has raised an event. This value is correct only in definition of some event handler
//! \~russian Возвращает %PIObject* который вызвал это событие. Значение допустимо только из методов обработчиков событий
PIObject * emitter() const {return emitter_;}
//! Virtual function executes after property with name "name" has been changed
virtual void propertyChanged(const PIString & name) {}
//! \~english Virtual function executes after property with name "name" has been changed
//! \~russian Виртуальная функция, вызывается после изменения любого свойства.
virtual void propertyChanged(const char * name) {}
EVENT1(deleted, PIObject *, o)
//! \events
//! \{
/** \fn void deleted(PIObject * o)
* @brief Raise before object delete
* \note This event raised from destructor, so use only "o" value,
* don`t try to cast deleted object to some subclass! */
//! \fn void deleted(PIObject * o)
//! \brief
//! \~english Raise before object delete
//! \~russian Вызывается перед удалением объекта
//! \~\warning
//! \~english
//! This event raised from destructor, so use only "o" numeric value,
//! don`t try to cast deleted object to some subclass!
//! \~russian
//! Это событие вызывается из деструктора, поэтому используйте
//! только численное значение "o", не надо кастовать его в другие типы!
//! \}
private:
struct __Connection {
__Connection(void * sl = 0, void * si = 0, const PIString & e = PIString(), PIObject * d_o = 0, void * d = 0, int ac = 0, PIObject * p = 0) {
slot = sl;
signal = si;
event = e;
eventID = e.hash();
dest_o = d_o;
dest = d;
args_count = ac;
performer = p;
functor = 0;
}
void destroy();
void * slot;
void * signal;
std::function<void()> * functor;
PIString event;
uint eventID;
PIObject * dest_o;
PIObject * performer;
void * dest;
int args_count;
};
struct __QueuedEvent {
__QueuedEvent(void * sl = 0, void * d = 0, PIObject * d_o = 0, PIObject * s = 0, const PIVector<PIVariantSimple> & v = PIVector<PIVariantSimple>()) {
slot = sl;
@@ -474,20 +553,16 @@ private:
static Deleter * instance();
void post(PIObject * o);
private:
void proc();
void deleteAll();
void deleteObject(PIObject * o);
std::atomic_bool stopping, started, posted;
PRIVATE_DECLARATION(PIP_EXPORT)
};
typedef PIPair<PIString, PIVariant> Property;
typedef PIPair<uint, PIPair<PIString, PIVariant> > PropertyHash;
bool findSuitableMethodV(const PIString & method, int args, int & ret_args, __MetaFunc & ret);
PIVector<__MetaFunc> findEH(const PIString & name) const;
__MetaFunc methodEH(const void * addr) const;
void updateConnectors();
void piDisconnectAll();
void postQueuedEvent(const __QueuedEvent & e);
void eventBegin() {in_event_cnt++;}
void eventEnd () {in_event_cnt--;}
@@ -500,8 +575,8 @@ private:
static void callAddrV(void * slot, void * obj, int args, const PIVector<PIVariantSimple> & vl);
PIVector<__Connection> connections;
PIMap<uint, PIPair<PIString, PIVariant> > properties_;
PIVector<Connection> connections;
PIMap<uint, PIVariant> properties_;
PISet<PIObject * > connectors;
PIVector<__QueuedEvent> events_queue;
PIMutex mutex_, mutex_connect, mutex_queue;
@@ -511,8 +586,9 @@ private:
};
PIP_EXPORT void dumpApplication();
PIP_EXPORT bool dumpApplicationToFile(const PIString & path);
#ifndef MICRO_PIP
PIP_EXPORT void dumpApplication(bool with_objects = true);
PIP_EXPORT bool dumpApplicationToFile(const PIString & path, bool with_objects = true);
#endif
#endif // PIOBJECT_H

View File

@@ -1,7 +1,8 @@
/*! @file piobject_macros.h
* @brief Base object
*
* This file declare macros for PIObject
/*! \file piobject_macros.h
* \ingroup Core
* \~\brief
* \~english PIObject macros
* \~russian Макросы PIObject
*/
/*
PIP - Platform Independent Primitives
@@ -29,67 +30,127 @@
#ifdef DOXYGEN
/// \relatesalso PIObject @brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER and correct piCoutObj output
//! \relatesalso PIObject
//! \~\brief
//! \~english You should use this macro after class declaration to use EVENT and EVENT_HANDLER and correct piCoutObj output
//! \~russian Необходимо использовать этот макрос после объявления класса для использования событийной системы и корректного вывода piCoutObj
#define PIOBJECT(name)
/// \relatesalso PIObject @brief you should use this macro after class declaration to use EVENT and EVENT_HANDLER of parent class, and \a scopeList()
//! \relatesalso PIObject
//! \~\brief
//! \~english You should use this macro after class declaration to use EVENT and EVENT_HANDLER of parent class, and \a scopeList()
//! \~russian
#define PIOBJECT_SUBCLASS(name, parent)
/// \relatesalso PIObject @brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name()
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event handler with name \"name\" and return type \"ret\", ret name()
//! \~russian Объявляет обработчик событий с именем \"name\" и возвращаемым типом \"ret\", ret name()
#define EVENT_HANDLER0(ret, name) ret name()
/// \relatesalso PIObject @brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event handler with name \"name\" and return type \"ret\", ret name(type0 var0)
//! \~russian Объявляет обработчик событий с именем \"name\" и возвращаемым типом \"ret\", ret name(type0 var0)
#define EVENT_HANDLER1(ret, name, type0, var0) ret name(type0 var0)
/// \relatesalso PIObject @brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event handler with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1)
//! \~russian Объявляет обработчик событий с именем \"name\" и возвращаемым типом \"ret\", ret name(type0 var0, type1 var1)
#define EVENT_HANDLER2(ret, name, type0, var0, type1, var1) ret name(type0 var0, type1 var1)
/// \relatesalso PIObject @brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event handler with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2)
//! \~russian Объявляет обработчик событий с именем \"name\" и возвращаемым типом \"ret\", ret name(type0 var0, type1 var1, type2 var2)
#define EVENT_HANDLER3(ret, name, type0, var0, type1, var1, type2, var2) ret name(type0 var0, type1 var1, type2 var2)
/// \relatesalso PIObject @brief declare event handler \"event\" with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2, type3 var3)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event handler with name \"name\" and return type \"ret\", ret name(type0 var0, type1 var1, type2 var2, type3 var3)
//! \~russian Объявляет обработчик событий с именем \"name\" и возвращаемым типом \"ret\", ret name(type0 var0, type1 var1, type2 var2, type3 var3)
#define EVENT_HANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) ret name(type0 var0, type1 var1, type2 var2, type3 var3)
/// \relatesalso PIObject @brief EVENT_HANDLER is synonym of EVENT_HANDLER0
//! \relatesalso PIObject
//! \~\brief
//! \~english Synonym of EVENT_HANDLER0
//! \~russian Аналог EVENT_HANDLER0
#define EVENT_HANDLER EVENT_HANDLER0
/// \relatesalso PIObject @brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name()
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare virtual event handler with name \"name\" and return type \"ret\", virtual ret name()
//! \~russian Объявляет виртуальный обработчик событий с именем \"name\" и возвращаемым типом \"ret\", virtual ret name()
#define EVENT_VHANDLER0(ret, name) virtual ret name()
/// \relatesalso PIObject @brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare virtual event handler with name \"name\" and return type \"ret\", virtual ret name(type0 var0)
//! \~russian Объявляет виртуальный обработчик событий с именем \"name\" и возвращаемым типом \"ret\", virtual ret name(type0 var0)
#define EVENT_VHANDLER1(ret, name, type0, var0) virtual ret name(type0 var0)
/// \relatesalso PIObject @brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare virtual event handler with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1)
//! \~russian Объявляет виртуальный обработчик событий с именем \"name\" и возвращаемым типом \"ret\", virtual ret name(type0 var0, type1 var1)
#define EVENT_VHANDLER2(ret, name, type0, var0, type1, var1) virtual ret name(type0 var0, type1 var1)
/// \relatesalso PIObject @brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare virtual event handler with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2)
//! \~russian Объявляет виртуальный обработчик событий с именем \"name\" и возвращаемым типом \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2)
#define EVENT_VHANDLER3(ret, name, type0, var0, type1, var1, type2, var2) virtual ret name(type0 var0, type1 var1, type2 var2)
/// \relatesalso PIObject @brief declare virtual event handler \"event\" with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare virtual event handler with name \"name\" and return type \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
//! \~russian Объявляет виртуальный обработчик событий с именем \"name\" и возвращаемым типом \"ret\", virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
#define EVENT_VHANDLER4(ret, name, type0, var0, type1, var1, type2, var2, type3, var3) virtual ret name(type0 var0, type1 var1, type2 var2, type3 var3)
/// \relatesalso PIObject @brief EVENT_VHANDLER is synonym of EVENT_VHANDLER0
//! \relatesalso PIObject
//! \~\brief
//! \~english Synonym of EVENT_VHANDLER0
//! \~russian Аналог EVENT_VHANDLER0
#define EVENT_VHANDLER EVENT_VHANDLER0
/// \relatesalso PIObject @brief declare event \"event\" with name \"name\", void name();
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event with name \"name\", void name();
//! \~russian Объявляет событие с именем \"name\", void name();
#define EVENT0(name) void name();
/// \relatesalso PIObject @brief declare event \"event\" with name \"name\", void name(type0 var0);
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event with name \"name\", void name(type0 var0);
//! \~russian Объявляет событие с именем \"name\", void name(type0 var0);
#define EVENT1(name, type0, var0) void name(type0 var0);
/// \relatesalso PIObject @brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1);
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event with name \"name\", void name(type0 var0, type1 var1);
//! \~russian Объявляет событие с именем \"name\", void name(type0 var0, type1 var1);
#define EVENT2(name, type0, var0, type1, var1) void name(type0 var0, type1 var1);
/// \relatesalso PIObject @brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2);
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event with name \"name\", void name(type0 var0, type1 var1, type2 var2);
//! \~russian Объявляет событие с именем \"name\", void name(type0 var0, type1 var1, type2 var2);
#define EVENT3(name, type0, var0, type1, var1, type2, var2) void name(type0 var0, type1 var1, type2 var2);
/// \relatesalso PIObject @brief declare event \"event\" with name \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3);
//! \relatesalso PIObject
//! \~\brief
//! \~english Declare event with name \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3);
//! \~russian Объявляет событие с именем \"name\", void name(type0 var0, type1 var1, type2 var2, type3 var3);
#define EVENT4(name, type0, var0, type1, var1, type2, var2, type3, var3) void name(type0 var0, type1 var1, type2 var2, type3 var3);
/// \relatesalso PIObject @brief EVENT is synonym of EVENT0
//! \relatesalso PIObject
//! \~\brief
//! \~english Synonym of EVENT0
//! \~russian Аналог EVENT0
#define EVENT EVENT0
@@ -101,81 +162,217 @@
#define RAISE_EVENT RAISE_EVENT0
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\". \"Event\" and \"handler\" must has equal argument lists.
//! \relatesalso PIObject
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler or event \"handler\" of object \"dest\".
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" объекта \"dest\".
//! \~\details
//! \~english
//! \"handler\" can handle subset arguments of \"event\".
//! Returns \a PIObject::Connection
//! \~russian
//! \"handler\" может принимать не все аргументы от \"event\".
//! Возвращает \a PIObject::Connection
#define CONNECTU(src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\".
/// Event handler will be executed by \"performer\". \"Event\" and \"handler\" must has equal argument lists.
//! \relatesalso PIObject
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler or event \"handler\" of object \"dest\".
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" объекта \"dest\".
//! \~\details
//! \~english
//! \"handler\" can handle subset arguments of \"event\".
//! Event handler will be executed by \"performer\" when \a PIObject::callQueuedEvents() called.
//! All argument types should be registered by \a REGISTER_VARIANT() macro, but many
//! common and PIP types already done.
//! Returns \a PIObject::Connection
//! \~russian
//! \"handler\" может принимать не все аргументы от \"event\".
//! Обработчик будет вызван объектом \"performer\" при вызове \a PIObject::callQueuedEvents().
//! Все типы аргументов должны быть зарегистрированы с помощью макроса \a REGISTER_VARIANT(),
//! однако многие стандартные и PIP типы уже там.
//! Возвращает \a PIObject::Connection
#define CONNECTU_QUEUED(src, event, dest, handler, performer)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to lambda-expression \"functor\". \"Event\" and \"functor\" must has equal argument lists.
//! \relatesalso PIObject
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to lambda-expression \"functor\".
//! \~russian Соединяет событие \"event\" объекта \"src\" к лямбда-функции \"functor\".
//! \~\details
//! \~english
//! \"event\" and \"functor\" must has equal argument lists.
//! You should parentness \"functor\" with () if this is complex lambda.
//! Returns \a PIObject::Connection
//! \~russian
//! \"event\" и \"functor\" должны иметь одинаковые аргументы.
//! В случае сложной лямбда-функции оберните её ().
//! Возвращает \a PIObject::Connection
#define CONNECTL(src, event, functor)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" с проверкой наличия события и обработчика.
//! \~\details
//! Returns PIObject::Connection
#define CONNECT0(ret, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" с проверкой наличия события и обработчика.
//! \~\details
//! Returns PIObject::Connection
#define CONNECT1(ret, type0, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" с проверкой наличия события и обработчика.
//! \~\details
//! Returns PIObject::Connection
#define CONNECT2(ret, type0, type1, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" с проверкой наличия события и обработчика.
//! \~\details
//! Returns PIObject::Connection
#define CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" with check of event and handler exists.
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" с проверкой наличия события и обработчика.
//! \~\details
//! Returns PIObject::Connection
#define CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
/// \relatesalso PIObject @brief CONNECT is synonym of CONNECT0
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Synonym of \a CONNECT0
//! \~russian Аналог \a CONNECT0
#define CONNECT CONNECT0
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" без проверки наличия события и обработчика.
#define WEAK_CONNECT0(ret, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" без проверки наличия события и обработчика.
#define WEAK_CONNECT1(ret, type0, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" без проверки наличия события и обработчика.
#define WEAK_CONNECT2(ret, type0, type1, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" без проверки наличия события и обработчика.
#define WEAK_CONNECT3(ret, type0, type1, type2, src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Connect event \"event\" from object \"src\" to event handler \"handler\" with return type \"ret\" from object \"dest\" without check of event exists
//! \~russian Соединяет событие \"event\" объекта \"src\" к обработчику или событию \"handler\" с возвращаемым типом \"ret\" объекта \"dest\" без проверки наличия события и обработчика.
#define WEAK_CONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
/// \relatesalso PIObject @brief WEAK_CONNECT is synonym of WEAK_CONNECT0
//! \relatesalso PIObject
//! \deprecated
//! \~english Use \a CONNECTU() instead
//! \~russian Используйте \a CONNECTU()
//! \~\brief
//! \~english Synonym of \a WEAK_CONNECT0
//! \~russian Аналог \a WEAK_CONNECT0
#define WEAK_CONNECT WEAK_CONNECT0
/// \relatesalso PIObject @brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \relatesalso PIObject
//! \~\brief
//! \~english piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \~russian piDisconnect событие \"event\" объекта \"src\" от обработчика или события \"handler\" с возвращаемым типом \"ret\" объекта \"dest\"
#define DISCONNECT0(ret, src, event, dest, handler)
/// \relatesalso PIObject @brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \relatesalso PIObject
//! \~\brief
//! \~english piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \~russian piDisconnect событие \"event\" объекта \"src\" от обработчика или события \"handler\" с возвращаемым типом \"ret\" объекта \"dest\"
#define DISCONNECT1(ret, type0, src, event, dest, handler)
/// \relatesalso PIObject @brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \relatesalso PIObject
//! \~\brief
//! \~english piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \~russian piDisconnect событие \"event\" объекта \"src\" от обработчика или события \"handler\" с возвращаемым типом \"ret\" объекта \"dest\"
#define DISCONNECT2(ret, type0, type1, src, event, dest, handler)
/// \relatesalso PIObject @brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \relatesalso PIObject
//! \~\brief
//! \~english piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \~russian piDisconnect событие \"event\" объекта \"src\" от обработчика или события \"handler\" с возвращаемым типом \"ret\" объекта \"dest\"
#define DISCONNECT3(ret, type0, type1, type2, src, event, dest, handler)
/// \relatesalso PIObject @brief piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \relatesalso PIObject
//! \~\brief
//! \~english piDisconnect event \"event\" from object \"src\" from event handler \"handler\" with return type \"ret\" from object \"dest\"
//! \~russian piDisconnect событие \"event\" объекта \"src\" от обработчика или события \"handler\" с возвращаемым типом \"ret\" объекта \"dest\"
#define DISCONNECT4(ret, type0, type1, type2, type3, src, event, dest, handler)
/// \relatesalso PIObject @brief DISCONNECT is synonym of DISCONNECT0
//! \relatesalso PIObject
//! \~\brief
//! \~english Synonym of \a DISCONNECT0
//! \~russian Аналог \a DISCONNECT0
#define DISCONNECT DISCONNECT0
/// \relatesalso PIObject @brief Returns pointer to events handler \"handler\"
//! \relatesalso PIObject
//! \~\brief
//! \~english Returns pointer to events handler \"handler\"
//! \~russian Возвращает указатель на обработчик события \"handler\"
#define HANDLER(handler)
#define PIOBJECT(name)
#define PIOBJECT_SUBCLASS(name)
#else
@@ -188,13 +385,14 @@
# define __PTYPE(t) __PIVariantTypeInfo__<t>::PureType
#endif
#define __VVALUE(t, v) v.value< __PTYPE(t) >()
#define __PIOBJECT_MAX_ARGS__ 4
#define PIOBJECT(name) \
protected: \
typedef name __PIObject__; \
public: \
static const PIString __classNameS() {static PIString ret = PIStringAscii(#name); return ret;} \
static const char * __classNameCC() {return #name;} \
static uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
virtual const char * className() const {return #name;} \
virtual uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \
@@ -214,7 +412,7 @@
__MetaData & eh(__meta_data()[id]); \
eh.eh_set << ehp.eh_set; \
eh.eh_func << ehp.eh_func; \
eh.addScope(__classNameS(), id); \
eh.addScope(__classNameCC(), id); \
} \
}; \
__BaseInitializer__ __base_init__;
@@ -234,7 +432,7 @@
eh.eh_func << ehp.eh_func; \
eh.scope_id = ehp.scope_id; \
eh.scope_list = ehp.scope_list; \
eh.addScope(__classNameS(), id); \
eh.addScope(__classNameCC(), id); \
} \
}; \
__ParentInitializer__ __parent_init__; \
@@ -246,92 +444,61 @@
#define PIOBJECT_SUBCLASS(name, parent) PIOBJECT(name) PIOBJECT_PARENT(parent)
#define __EH_INIT_BASE__(ret, name) \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameCC(); \
f.__setFuncName(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = #ret;
#define EH_INIT0(ret, name) \
STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*))__stat_eh_##name##__; \
void * fpV = fp; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
__EH_INIT_BASE__(ret, name) \
STATIC_INITIALIZER_END
#define EH_INIT1(ret, name, a0, n0) \
STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0); \
f.names << PIStringAscii(#n0); \
__EH_INIT_BASE__(ret, name) \
f.__addArgument(#a0, #n0); \
STATIC_INITIALIZER_END
#define EH_INIT2(ret, name, a0, n0, a1, n1) \
STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1); \
f.names << PIStringAscii(#n0) << PIStringAscii(#n1); \
__EH_INIT_BASE__(ret, name) \
f.__addArgument(#a0, #n0); \
f.__addArgument(#a1, #n1); \
STATIC_INITIALIZER_END
#define EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1, a2))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &, const PIVariantSimple &, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2); \
f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2); \
__EH_INIT_BASE__(ret, name) \
f.__addArgument(#a0, #n0); \
f.__addArgument(#a1, #n1); \
f.__addArgument(#a2, #n2); \
STATIC_INITIALIZER_END
#define EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1, a2, a3))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &, const PIVariantSimple &, const PIVariantSimple &, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \
eh.eh_set << fp; \
__MetaFunc & f(eh.eh_func[fp]); \
f.scope = __classNameS(); \
f.func_name = PIStringAscii(#name); \
f.addr = fp; \
f.addrV = fpV; \
f.type_ret = PIStringAscii(#ret); \
f.types << PIObject::simplifyType(#a0) << PIObject::simplifyType(#a1) << PIObject::simplifyType(#a2) << PIObject::simplifyType(#a3); \
f.names << PIStringAscii(#n0) << PIStringAscii(#n1) << PIStringAscii(#n2) << PIStringAscii(#n3); \
__EH_INIT_BASE__(ret, name) \
f.__addArgument(#a0, #n0); \
f.__addArgument(#a1, #n1); \
f.__addArgument(#a2, #n2); \
f.__addArgument(#a3, #n3); \
STATIC_INITIALIZER_END

View File

@@ -20,6 +20,62 @@
#include "pipropertystorage.h"
//! \addtogroup Core
//! \{
//! \~\class PIPropertyStorage pipropertystorage.h
//! \~\brief
//! \~english This class provides key-value properties storage
//! \~russian Этот класс предоставляет ключ-значение хранение свойств
//!
//! \~\details
//! \~english \section PIPropertyStorage_sec0 Synopsis
//! \~russian \section PIPropertyStorage_sec0 Краткий обзор
//!
//! \~english
//! Key-value storage, based on PIVector with PIPropertyStorage::Property elements. Each element in vector
//! contains unique name. You can access property by name with \a propertyValueByName() or \a propertyByName().
//! You can add or replace property by \a addProperty(const Property&) or \a addProperty(const PIString&, const PIVariant&, const PIString&, int).
//!
//! \~russian
//! Хранилище свойств ключ-значние, основанный на PIVector с элементами PIPropertyStorage::Property.
//! Каждый элемент имеет уникальное имя. Доступ к свойствам через \a propertyValueByName() или \a propertyByName().
//! Добавление и перезапись свойств через \a addProperty(const Property&) или \a addProperty(const PIString&, const PIVariant&, const PIString&, int).
//!
//! \~english Example:
//! \~russian Пример:
//! \~\code{.cpp}
//! \endcode
//! \}
//! \addtogroup Core
//! \{
//! \~\class PIPropertyStorage::Property pipropertystorage.h
//! \~\brief
//! \~english PIPropertyStorage element
//! \~russian Элемент PIPropertyStorage
//!
//! \~\details
//! \~english \section PIPropertyStorage_sec1 Synopsis
//! \~russian \section PIPropertyStorage_sec1 Краткий обзор
//!
//! \~english
//! Key-value storage, based on PIVector with PIPropertyStorage::Property elements. Each element in vector
//! contains unique name. You can access property by name with \a propertyValueByName() or \a propertyByName().
//! You can add or replace property by \a addProperty(const Property&) or \a addProperty(const PIString&, const PIVariant&, const PIString&, int).
//!
//! \~russian
//! Хранилище свойств ключ-значние, основанный на PIVector с элементами PIPropertyStorage::Property.
//! Каждый элемент имеет уникальное имя. Доступ к свойствам через \a propertyValueByName() или \a propertyByName().
//! Добавление и перезапись свойств через \a addProperty(const Property&) или \a addProperty(const PIString&, const PIVariant&, const PIString&, int).
//!
//! \~english Example:
//! \~russian Пример:
//! \~\code{.cpp}
//! \endcode
//! \}
bool PIPropertyStorage::isPropertyExists(const PIString & _name) const {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == _name)
@@ -28,6 +84,9 @@ bool PIPropertyStorage::isPropertyExists(const PIString & _name) const {
}
//! \details
//! \~english Returns "true" if new property added, else if update existing property return "false"
//! \~russian Возвращает истину если новое свойство добавлено, в случае обновления "ложь"
bool PIPropertyStorage::addProperty(const PIPropertyStorage::Property & p) {
for (uint i = 0; i < props.size(); ++i)
if (props[i].name == p.name) {
@@ -50,6 +109,9 @@ bool PIPropertyStorage::addProperty(PIPropertyStorage::Property && p) {
}
//! \details
//! \~english Returns "true" if new property added, else if update existing property return "false"
//! \~russian Возвращает истину если новое свойство добавлено, в случае обновления "ложь"
bool PIPropertyStorage::addProperty(const PIString & _name, const PIVariant & _def_value, const PIString & _comment, int _flags) {
return addProperty(Property(_name, _comment, _def_value, _flags));
}
@@ -66,6 +128,9 @@ bool PIPropertyStorage::removeProperty(const PIString & _name) {
}
//! \details
//! \~english "flag" checked as bitfield
//! \~russian "flag" проверяется как битовое поле
int PIPropertyStorage::removePropertiesByFlag(int flag) {
int ret = 0;
for (int i = 0; i < props.size_s(); ++i) {
@@ -79,6 +144,9 @@ int PIPropertyStorage::removePropertiesByFlag(int flag) {
}
//! \details
//! \~english "flag_ignore" is bitfield to ignore property in merge process
//! \~russian "flag_ignore" - битовое поле для исключения свойств из процесса слияния
void PIPropertyStorage::updateProperties(const PIVector<PIPropertyStorage::Property> & properties_, int flag_ignore) {
PIMap<PIString, PIVariant> values;
piForeachC(Property & p, props)

View File

@@ -1,8 +1,9 @@
/*! @file pipropertystorage.h
* @brief Storage of properties for GUI usage
*
* This file declare PIPropertyStorage
*/
/*! \file pipropertystorage.h
* \ingroup Core
* \~\brief
* \~english Properties array
* \~russian Массив свойств
*/
/*
PIP - Platform Independent Primitives
Storage of properties for GUI usage
@@ -27,25 +28,28 @@
#include "pivariant.h"
/**
* @brief Key-value storage, based on PIVector with PIPropertyStorage::Property elements. Each element in vector
* contains unique name and you can identify property by name with propertyValueByName(), propertyByName().
* You can add property using addProperty(const Property&), addProperty(const PIString&, const PIVariant&, const PIString&, int).
*/
class PIP_EXPORT PIPropertyStorage {
public:
//! \~english Contructs an empty %PIPropertyStorage
//! \~russian Создает пустой %PIPropertyStorage
PIPropertyStorage() {}
/**
* @brief PIPropertyStorage element.
*/
struct PIP_EXPORT Property {
Property(const PIString & n = PIString(), const PIString & c = PIString(), const PIVariant & v = PIVariant(), int f = 0):
name(n), comment(c), value(v), flags(f) {}
Property(const Property & o):
name(o.name), comment(o.comment), value(o.value), flags(o.flags) {}
//! \~english Contructs %PIPropertyStorage::Property with name "n", comment "c", value "v" and flags "f"
//! \~russian Создает %PIPropertyStorage::Property с именем "n", комментарием "c", значением "v" и флагами "f"
Property(const PIString & n = PIString(), const PIString & c = PIString(), const PIVariant & v = PIVariant(), int f = 0): name(n), comment(c), value(v), flags(f) {}
//! \~english Contructs copy of another %PIPropertyStorage::Property "o"
//! \~russian Создает копию %PIPropertyStorage::Property "o"
Property(const Property & o): name(o.name), comment(o.comment), value(o.value), flags(o.flags) {}
Property(Property && o) {swap(o);}
//! \~english Assign operator
//! \~russian Оператор присваивания
Property & operator =(const Property & v) {
name = v.name;
comment = v.comment;
@@ -56,10 +60,24 @@ public:
Property & operator =(Property && v) {swap(v); return *this;}
//! \~english Returns value as boolean
//! \~russian Возвращает значение как логическое
bool toBool() const {return value.toBool();}
//! \~english Returns value as integer
//! \~russian Возвращает значение как целое
int toInt() const {return value.toInt();}
//! \~english Returns value as float
//! \~russian Возвращает значение как float
float toFloat() const {return value.toFloat();}
//! \~english Returns value as double
//! \~russian Возвращает значение как double
double toDouble() const {return value.toDouble();}
//! \~english Returns value as string
//! \~russian Возвращает значение как строку
PIString toString() const {return value.toString();}
void swap(Property & o) {
@@ -69,22 +87,30 @@ public:
piSwap(flags, o.flags);
}
/*! Uniqueue id of property */
//! \~english Property name (uniqueue for %PIPropertyStorage)
//! \~russian Имя свойства (уникальное для %PIPropertyStorage)
PIString name;
/*! Optional description of property */
//! \~english Optional description of property
//! \~russian Опциональный комментарий свойства
PIString comment;
/*! Custom value of property */
//! \~english Property value
//! \~russian Значение свойства
PIVariant value;
/*! Abstract flags which may be used for user needs */
//! \~english Abstract flags which may be used for user needs
//! \~russian Абстрактные флаги, могут быть использованы для своих нужд
int flags;
};
//! \~english Contructs %PIPropertyStorage with "pl" properties
//! \~russian Создает %PIPropertyStorage со свойствами "pl"
PIPropertyStorage(const PIVector<Property> & pl) {props = pl;}
PIPropertyStorage(PIVector<Property> && pl): props(std::move(pl)) {}
//! \~english Contructs %PIPropertyStorage from another "o"
//! \~russian Создает %PIPropertyStorage из другого "o"
PIPropertyStorage(PIVector<Property> && o): props(std::move(o)) {}
typedef PIVector<Property>::const_iterator const_iterator;
typedef PIVector<Property>::iterator iterator;
@@ -95,118 +121,141 @@ public:
iterator end() {return props.end();}
const_iterator end() const {return props.end();}
//! \~english Returns properties count
//! \~russian Возвращает количество свойств
int length() const {return props.length();}
//! \~english Returns properties count
//! \~russian Возвращает количество свойств
int size() const {return props.size();}
//! \~english Returns if no properties
//! \~russian Возвращает нет ли свойств
bool isEmpty() const {return props.isEmpty();}
//! \~english Returns if properties
//! \~russian Возвращает есть ли свойства
bool isNotEmpty() const {return props.isNotEmpty();}
//! \~english Returns first property
//! \~russian Возвращает первое свойство
Property & front() {return props.front();}
//! \~english Returns first property as const
//! \~russian Возвращает первое свойство как константу
const Property & front() const {return props.front();}
//! \~english Returns last property
//! \~russian Возвращает последнее свойство
Property & back() {return props.back();}
//! \~english Returns last property as const
//! \~russian Возвращает последнее свойство как константу
const Property & back() const {return props.back();}
//! \~english Remove property at index "i"
//! \~russian Удаляет свойство по индексу "i"
void removeAt(int i) {props.remove(i);}
//! \~english Remove all properties
//! \~russian Удаляет все свойства
void clear() {props.clear();}
//! \~english Returns copy of this %PIPropertyStorage
//! \~russian Возвращает копию этого %PIPropertyStorage
PIPropertyStorage copy() const {return PIPropertyStorage(*this);}
//! \~english Returns properties count
//! \~russian Возвращает количество свойств
int propertiesCount() const {return props.size();}
//! \~english Returns properties as PIVector
//! \~russian Возвращает свойства как PIVector
PIVector<Property> & properties() {return props;}
//! \~english Returns properties as const PIVector
//! \~russian Возвращает свойства как константный PIVector
const PIVector<Property> & properties() const {return props;}
const PIPropertyStorage & propertyStorage() const {return *this;}
/**
* @brief Check if property with \a name exists
* @return "true" if property exists
*/
bool isPropertyExists(const PIString & _name) const;
//! \~english Returns if properties with name "name" exists
//! \~russian Возвращает присутствует ли свойство с именем "name"
bool isPropertyExists(const PIString & name) const;
/**
* @brief Remove all properties
*/
//! \~english Remove all properties
//! \~russian Удаляет все свойства
void clearProperties() {props.clear();}
/**
* @brief Add property if name isn't present in storage, otherwrise update existing property with same name.
* @return "true" if new property added, else if update existing property return "false"
* @param p to copy in storage
*/
//! \~english Add property if name isn't present in storage, otherwrise update existing property with same name
//! \~russian Добавляет новое свойство, если его имени не было в контейнере, иначе обновляет существующее свойство с этим именем
bool addProperty(const Property & p);
bool addProperty(Property && p);
/**
* @brief First of all construct Property with method params. After then add property if name isn't present
* in storage, otherwrise update existing property with same name.
* @return "true" if new property added, else if update existing property return "false"
*/
//! \~english Add property if name isn't present in storage, otherwrise update existing property with same name
//! \~russian Добавляет новое свойство, если его имени не было в контейнере, иначе обновляет существующее свойство с этим именем
bool addProperty(const PIString & _name, const PIVariant & _def_value, const PIString & _comment = PIString(), int _flags = 0);
/**
* @brief Remove property with \a name
* @return "true" if property exists and removed
*/
bool removeProperty(const PIString & _name);
//! \~english Remove property with name "name", returns if property removed
//! \~russian Удаляет свойство с именем "name", возвращает было ли оно удалено
bool removeProperty(const PIString & name);
/**
* @brief Remove properties wich has \a flag set
* @return removed properties count
*/
//! \~english Remove all properties with flag "flag" set, returns removed properties count
//! \~russian Удаляет все свойства с флагом "flag", возвращает количество удаленных свойств
int removePropertiesByFlag(int flag);
/**
* @brief Merge other \a properties_ into this
* @param flag_ignore - properties wich has this flag set will be ignored in merge
*/
void updateProperties(const PIVector<Property> & properties_, int flag_ignore = 0);
//! \~english Merge other "properties" into this
//! \~russian Объединяет "properties" с текущим контейнером
void updateProperties(const PIVector<Property> & properties, int flag_ignore = 0);
/**
* @brief Search property by name and return it.
*
* @param name of property
* @return property value or default constructed Property
*/
//! \~english Returns property with name "name" or default-constructed %PIPropertyStorage::Property
//! \~russian Возвращает свойство с именем "name" или пустое %PIPropertyStorage::Property
Property propertyByName(const PIString & name) const;
/**
* @brief Search property by name and return property value.
*
* @param name of property
* @return property value or invalid PIVariant if name unknown
*/
//! \~english Returns property value with name "name" or invalid %PIVariant
//! \~russian Возвращает значение свойства с именем "name" или недействительный %PIVariant
PIVariant propertyValueByName(const PIString & name) const;
/**
* @brief Set value of property with specific name if name is present in storage.
*
* @param name of property to set value
* @param value to set
* @return "true" if property exists and updated
*/
//! \~english Set value of property with name "name" to "value", returns if property exists
//! \~russian Устанавливает значение "value" свойству с именем "name", возвращает существует ли такое свойство
bool setPropertyValue(const PIString & name, const PIVariant & value);
/**
* @brief Set comment of property with specific name if name is present in storage.
*
* @param name of property to set comment
* @param comment to set
* @return "true" if property exists and updated
*/
//! \~english Set comment of property with name "name" to "comment", returns if property exists
//! \~russian Устанавливает комментарий "comment" свойству с именем "name", возвращает существует ли такое свойство
bool setPropertyComment(const PIString & name, const PIString & comment);
/**
* @brief Set flags of property with specific name if name is present in storage.
*
* @param name of property to set flags
* @param flags to set
* @return "true" if property exists and updated
*/
//! \~english Set flags of property with name "name" to "flags", returns if property exists
//! \~russian Устанавливает флаги "flags" свойству с именем "name", возвращает существует ли такое свойство
bool setPropertyFlags(const PIString & name, int flags);
//! \~english Add property "p"
//! \~russian Добавляет свойство "p"
PIPropertyStorage & operator <<(const PIPropertyStorage::Property & p) {props << p; return *this;}
PIPropertyStorage & operator <<(const PIVector<Property> & p) {props << p; return *this;}
PIPropertyStorage & operator <<(const PIPropertyStorage & p) {props << p.props; return *this;}
Property & operator[](int i) {return props[i];}
const Property & operator[](int i) const {return props[i];}
Property & operator[](const PIString & name);
const Property operator[](const PIString & name) const;
static Property parsePropertyLine(PIString l);
//! \~english Add properties "p"
//! \~russian Добавляет свойства "p"
PIPropertyStorage & operator <<(const PIVector<Property> & p) {props << p; return *this;}
//! \~english Add properties "p"
//! \~russian Добавляет свойства "p"
PIPropertyStorage & operator <<(const PIPropertyStorage & p) {props << p.props; return *this;}
//! \~english Returns property with index "i"
//! \~russian Возвращает свойство по индексу "i"
Property & operator[](int i) {return props[i];}
//! \~english Returns property with index "i" as const
//! \~russian Возвращает свойство по индексу "i" как константу
const Property & operator[](int i) const {return props[i];}
//! \~english Returns property with name "name"
//! \~russian Возвращает свойство с именем "name"
Property & operator[](const PIString & name);
//! \~english Returns property with name "name" as const
//! \~russian Возвращает свойство с именем "name" как константу
const Property operator[](const PIString & name) const;
protected:
PIVector<Property> props;

View File

@@ -27,99 +27,46 @@
#ifdef WINDOWS
# include <stringapiset.h>
#endif
#include <wchar.h>
#ifdef ANDROID
# if __ANDROID_API__ < 21
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
# endif
#endif
#include <string>
#include <locale>
#include <codecvt>
/*! \class PIString
* @brief String class
* \details PIP use this class for use string information.
*
* \section PIString_sec0 Synopsis
* This class based on \a PIVector to store information.
* String is a sequence of \a PIChar and can contain multibyte
* symbols. Therefore real memory size of string is symbols count * 4.
* String can be constucted from many types of data and can be converted
* to many types. There are man operators and handly functions to use
* string as you wish.
*
* \section PIString_sec1 To/from data convertions
* Most common constructor is \a PIString(const char * str), where "str"
* is null-terminated string, e.g. \c "string". This is 7 chars with last char = 0.
* Also you can constructs \a PIString from single \a PIChar, \a PIByteArray,
* other \a PIString or sequency of the same characters with custom length.\n \n
* This class has implicit conversions to <tt>const char * </tt> and
* \c std::string. Also there are functions to make same convertions:
* * \a data() - to <tt>const char * </tt>,
* * \a stdString() - to \c std::string,
* * \a toByteArray() - to \a PIByteArray.
*
* \section PIString_sec2 Numeric operations
* You can get symbolic representation of any numeric value with function
* \a setNumber(any integer value, int base = 10, bool * ok = 0). Default
* arguments are set for decimal base system, but you can choose any system
* from 2 to 40. There are the same static functions \a fromNumber(), that
* returns \a PIString. \n
* Also there is function \a setReadableSize() which is set human-readable
* size in bytes, Kb, Mb, Gb or Pb. Static analog is \a readableSize().
*
*/
//! \addtogroup Core
//! \{
//! \class PIString pistring.h
//! \brief
//! \~english String class
//! \~russian Класс строки
//!
//! \~\details
//! \~english \section PIString_sec0 Synopsis
//! \~russian \section PIString_sec0 Краткий обзор
//!
//! \~english
//! String is a sequence of \a PIChar. Real memory size of string is symbols count * 2.
//! String can be constucted from many types of data and can be converted
//! to many types. There are many operators and handly functions to use
//! string as you wish.
//!
//! \~russian
//! Строка состоит из последовательности \a PIChar. Реальный объем памяти,
//! занимаемый строкой, равен количеству символов * 2. Строка может быть
//! создана из множества типов и преобразована в несколько типов.
//! Имеет множество методов для манипуляций.
//!
//! \}
/*! \fn int versionCompare(const PIString & v0, const PIString & v1, int components = 6)
* \relatesalso PIString
* @brief Compare two version strings in free notation and returns 0, -1 or 1
* \details This function parse version to number codes and labels. Then it
* compare no more than "components" codes. If there is no difference, compare
* labels. Each label has corresponding integer value, so
* "prealpha" < "alpha" < "prebeta" < "beta" < "rcN" < "" < "rN".
* Example:
* \code
* piCout << versionCompare("1.0.0_rc2-999", "1.0.1_rc2-999"); // -1
* piCout << versionCompare("1.0.0", "0.9.2"); // 1
* piCout << versionCompare("1.0.0_r1", "1.0.0"); // 1
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
* piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0
* piCout << versionCompare(".2-alpha", "0.2_alpha"); // 0
* piCout << versionCompare("1_prebeta", "1.0_alpha"); // 1
* \endcode
* \return
* * 0 - equal
* * 1 - v0 > v1
* * -1 - v0 < v1
*
*
* \fn PIString versionNormalize(const PIString & v)
* \relatesalso PIString
* @brief Converts version string in free notation to classic view
* \details Parse version as described in \a versionCompare() and
* returns classic view of codes and labels: major.minor.revision[-build][_label].
* Example:
* \code
* piCout << versionNormalize(""); // 0.0.0
* piCout << versionNormalize("1"); // 1.0.0
* piCout << versionNormalize("1.2"); // 1.2.0
* piCout << versionNormalize("1.2.3"); // 1.2.3
* piCout << versionNormalize("1.2+rc1.99"); // 1.2.99_rc1
* piCout << versionNormalize("1.2-alpha"); // 1.2.0_alpha
* piCout << versionNormalize("1..4_rc2-999"); // 1.0.4-999_rc2
* \endcode
*
*/
const char PIString::toBaseN[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
const char PIString::toBaseN[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^'};
const int PIString::fromBaseN[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
const char PIString::fromBaseN[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
@@ -138,35 +85,21 @@ const float PIString::ElideCenter = .5f;
const float PIString::ElideRight = 1.f;
#ifndef CC_VC
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf(ch, f, v);
#else
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf_s(ch, 256, f, v);
#endif
#ifdef ANDROID
//int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
#endif
PIString PIString::itos(const int num) {pisprintf("%d", num); return PIString(ch);}
PIString PIString::ltos(const long num) {pisprintf("%ld", num); return PIString(ch);}
PIString PIString::lltos(const llong num) {pisprintf("%lld", num); return PIString(ch);}
PIString PIString::uitos(const uint num) {pisprintf("%u", num); return PIString(ch);}
PIString PIString::ultos(const ulong num) {pisprintf("%lu", num); return PIString(ch);}
PIString PIString::ulltos(const ullong num) {pisprintf("%llu", num); return PIString(ch);}
PIString PIString::ftos(const float num, char format, int precision) {
char f[8] = "%.";
int wr = sprintf(&(f[2]), "%d", precision);
f[2 + wr] = format;
f[3 + wr] = 0;
pisprintf(f, num);
return PIString(ch);
}
#define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); snprintf(ch, 256, f, v); return PIStringAscii(ch);
PIString PIString::itos(const int num) {pisprintf("%d", num);}
PIString PIString::ltos(const long num) {pisprintf("%ld", num);}
PIString PIString::lltos(const llong num) {pisprintf("%lld", num);}
PIString PIString::uitos(const uint num) {pisprintf("%u", num);}
PIString PIString::ultos(const ulong num) {pisprintf("%lu", num);}
PIString PIString::ulltos(const ullong num) {pisprintf("%llu", num);}
PIString PIString::dtos(const double num, char format, int precision) {
char f[8] = "%.";
int wr = sprintf(&(f[2]), "%d", precision);
int wr = snprintf(&(f[2]), 4, "%d", precision);
if (wr > 4) wr = 4;
f[2 + wr] = format;
f[3 + wr] = 0;
pisprintf(f, num);
return PIString(ch);
}
#undef pisprintf
@@ -174,7 +107,10 @@ PIString PIString::dtos(const double num, char format, int precision) {
PIString PIString::fromNumberBaseS(const llong value, int base, bool * ok) {
if (value == 0LL) return PIString('0');
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
if ((base < 2) || (base > 40)) {
if (ok != 0) *ok = false;
return PIString();
}
if (ok != 0) *ok = true;
if (base == 10) return lltos(value);
PIString ret;
@@ -193,7 +129,10 @@ PIString PIString::fromNumberBaseS(const llong value, int base, bool * ok) {
PIString PIString::fromNumberBaseU(const ullong value, int base, bool * ok) {
if (value == 0ULL) return PIString('0');
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return PIString();}
if ((base < 2) || (base > 40)) {
if (ok != 0) *ok = false;
return PIString();
}
if (ok != 0) *ok = true;
if (base == 10) return ulltos(value);
PIString ret;
@@ -215,17 +154,26 @@ llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
PIString v = value.trimmed();
if (base < 0) {
int ind = v.find(s_0x);
if (ind == 0 || ind == 1) {v.remove(ind, 2); base = 16;}
else base = 10;
} else
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return 0;}
if (ind == 0 || ind == 1) {
v.remove(ind, 2);
base = 16;
} else {
base = 10;
}
} else if ((base < 2) || (base > 40)) {
if (ok != 0) *ok = false;
return 0;
}
if (ok) *ok = true;
PIVector<int> digits;
llong ret = 0, m = 1;
bool neg = false;
int cs;
char cs;
for (int i = 0; i < v.size_s(); ++i) {
if (v[i] == PIChar('-')) {neg = !neg; continue;}
if (v[i] == PIChar('-')) {
neg = !neg;
continue;
}
cs = fromBaseN[int(v[i].toAscii())];
if (cs < 0 || cs >= base) {
if (ok) *ok = false;
@@ -243,113 +191,87 @@ llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
void PIString::appendFromChars(const char * c, int s, const char * codepage) {
if (s <= 0) return;
int sz;
// piCout << "appendFromChars";
if (s == 0) return;
int old_sz = size_s();
if (s == -1) s = strlen(c);
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(codepage, &e);
if (cc) {
UChar * ucs = new UChar[s];
memset(ucs, 0, s * sizeof(UChar));
d.enlarge(s);
e = (UErrorCode)0;
int sz = ucnv_toUChars(cc, ucs, s, c, s, &e);
//printf("appendFromChars %d -> %d\n", s, sz);
//printf("PIString %d -> %d\n", c[0], ucs[0]);
reserve(size_s() + sz);
for (int i = 0; i < sz; ++i)
push_back(PIChar(ucs[i]));
delete[] ucs;
int sz = ucnv_toUChars(cc, (UChar*)(d.data(old_sz)), s, c, s, &e);
d.resize(old_sz+sz);
ucnv_close(cc);
return;
}
#else
# ifdef WINDOWS
sz = MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, 0, 0);
int sz = MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, 0, 0);
if (sz <= 0) return;
int old_sz = size_s();
enlarge(sz);
MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, (LPWSTR)PIDeque<PIChar>::data(old_sz), sz);
return;
//printf("request %d\n", sz);
d.enlarge(sz);
MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, (LPWSTR)d.data(old_sz), sz);
# else
wchar_t wc;
mbtowc(0,0,0); // reset mbtowc
//qDebug() << "FromChars ...";
while (s>0) {
//qDebug() << "0" << s;
sz = mbtowc(&wc, c, s);
//qDebug() << "1" << sz;
if (sz < 1) break;
push_back(PIChar(int(wc)));
c += sz; s -= sz;
//qDebug() << "2" << c;
}
//qDebug() << "FromChars done" << size();
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> ucs2conv;
std::u16string ucs2 = ucs2conv.from_bytes(c, c+s);
d.enlarge(ucs2.size());
ucs2.copy((char16_t *)d.data(old_sz), ucs2.size());
# endif
#endif
}
PIString PIString::fromConsole(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l, __sysoemname__);
if (!s) return ret;
if (s[0] != '\0') ret.appendFromChars(s, -1, __sysoemname__);
return ret;
}
PIString PIString::fromSystem(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l, __syslocname__);
if (!s) return ret;
if (s[0] != '\0') ret.appendFromChars(s, -1, __syslocname__);
return ret;
}
PIString PIString::fromUTF8(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l, __utf8name__);
if (!s) return ret;
if (s[0] != '\0') ret.appendFromChars(s, -1, __utf8name__);
return ret;
}
PIString PIString::fromUTF8(const PIByteArray & ba) {
PIString ret;
if (ba.isEmpty()) return ret;
ret.appendFromChars((const char*)ba.data(), ba.size(), __utf8name__);
if (ba.isNotEmpty()) ret.appendFromChars((const char*)ba.data(), ba.size(), __utf8name__);
return ret;
}
PIString PIString::fromAscii(const char * s) {
PIString ret;
int l = 0;
while (s[l] != '\0') {
ret.push_back(PIChar(s[l]));
++l;
}
return ret;
return fromAscii(s, strlen(s));
}
PIString PIString::fromAscii(const char * s, int len) {
PIString ret;
for (int l = 0; l < len; ++l)
ret.push_back(PIChar(s[l]));
ret.resize(len);
for (int l = 0; l < len; ++l) {
ret[l] = s[l];
}
return ret;
}
PIString PIString::fromCodepage(const char * s, const char * c) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret;
if (l > 0) ret.appendFromChars(s, l
if (s[0] > '\0') ret.appendFromChars(s, -1
#ifdef PIP_ICU
, c
#else
@@ -362,6 +284,19 @@ PIString PIString::fromCodepage(const char * s, const char * c) {
}
//! \~\details
//! \~english
//! Example:
//! \~russian
//! Пример:
//! \~\code
//! 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
//! \endcode
PIString PIString::readableSize(llong bytes) {
PIString s;
s.setReadableSize(bytes);
@@ -370,107 +305,78 @@ PIString PIString::readableSize(llong bytes) {
void PIString::buildData(const char * cp) const {
data_.clear();
int sz = 0;
deleteData();
#ifdef PIP_ICU
UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(cp, &e);
if (cc) {
char uc[8];
data_.reserve(size_s());
for (int i = 0; i < size_s(); ++i) {
if (at(i).isAscii())
data_.push_back(uchar(at(i).unicode16Code()));
else {
e = (UErrorCode)0;
sz = ucnv_fromUChars(cc, uc, 8, (const UChar*)(PIDeque<PIChar>::data(i)), 1, &e);
for (int j = 0; j < sz; ++j)
data_.push_back(uc[j]);
}
}
const size_t len = MB_CUR_MAX*size()+1;
data_ = (char *)malloc(len);
int sz = ucnv_fromUChars(cc, data_, len, (const UChar*)(d.data()), d.size_s(), &e);
ucnv_close(cc);
data_.push_back('\0');
data_[sz] = '\0';
return;
}
#else
# ifdef WINDOWS
sz = WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), 0, 0, NULL, NULL);
//printf("WideCharToMultiByte %d %d\n", (uint)(uintptr_t)cp, sz);
int sz = WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)d.data(), d.size_s(), 0, 0, NULL, NULL);
if (sz <= 0) {
//printf("WideCharToMultiByte erro %d\n", GetLastError());
data_.push_back(uchar('\0'));
data_ = (char *)malloc(1);
data_[0] = '\0';
return;
}
data_.resize(sz);
WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), (LPSTR)data_.data(), data_.size_s(), NULL, NULL);
data_.push_back(uchar('\0'));
data_ = (char *)malloc(sz+1);
WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)d.data(), d.size_s(), (LPSTR)data_, sz, NULL, NULL);
data_[sz] = '\0';
return;
# else
wchar_t wc;
char tc[8];
wctomb(0, 0);
for (int i = 0; i < size_s(); ++i) {
if (at(i).isAscii()) {
data_.push_back(uchar(at(i).toAscii()));
continue;
}
wc = at(i).toWChar();
sz = wctomb(tc, wc);
for (int b = 0; b < sz; ++b)
data_.push_back(uchar(tc[b]));
}
data_.push_back(uchar('\0'));
std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> ucs2conv;
std::string u8str = ucs2conv.to_bytes((char16_t*)d.data(), (char16_t*)d.data() + d.size());
data_ = (char *)malloc(u8str.size()+1);
strcpy(data_, u8str.c_str());
# endif
#endif
}
void PIString::deleteData() const {
if (!data_) return;
free(data_);
data_ = nullptr;
}
void PIString::trimsubstr(int &st, int &fn) const {
for (int i = 0; i < length(); ++i)
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0))
{st = i; break;}
for (int i = 0; i < d.size_s(); ++i) {
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0)) {
st = i;
break;
}
}
if (st < 0) return;
for (int i = length() - 1; i >= 0; --i)
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0))
{fn = i; break;}
}
const char * PIString::dataConsole() const {
buildData(__sysoemname__ );
return (const char *)(data_.data());
}
const char * PIString::dataUTF8() const {
buildData(__utf8name__);
return (const char *)(data_.data());
}
const char * PIString::dataAscii() const {
data_.clear();
for (int i = 0; i < size_s(); ++i)
data_.push_back(uchar(at(i).ch));
data_.push_back(uchar('\0'));
return (const char *)data_.data();
for (int i = d.size_s() - 1; i >= 0; --i) {
if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0)) {
fn = i;
break;
}
}
}
uint PIString::hash() const {
return piHashData((const uchar*)PIDeque<PIChar>::data(), size() * sizeof(PIChar));
return piHashData((const uchar*)d.data(), d.size() * sizeof(PIChar));
}
PIByteArray PIString::toUTF8() const {
if (isEmpty()) return data_.resized(0);
if (isEmpty()) return PIByteArray();
buildData(__utf8name__);
return data_.resized(data_.size_s() - 1);
return PIByteArray(data_, strlen(data_));
}
PIByteArray PIString::toCharset(const char * c) const {
if (isEmpty()) return data_.resized(0);
if (isEmpty()) return PIByteArray();
buildData(
#ifdef PIP_ICU
c
@@ -480,62 +386,67 @@ PIByteArray PIString::toCharset(const char * c) const {
# endif
#endif
);
return data_.resized(data_.size_s() - 1);
return PIByteArray(data_, strlen(data_));
}
PIString & PIString::operator +=(const char * str) {
if (!str) return *this;
int l = 0;
while (str[l] != '\0') ++l;
appendFromChars(str, l, __syslocname__);
appendFromChars(str, -1, __syslocname__);
return *this;
}
PIString::~PIString() {
deleteData();
}
PIString & PIString::operator +=(const wchar_t * str) {
if (!str) return *this;
int i = -1;
while (str[++i])
push_back(PIChar(ushort(str[i])));
while (str[++i]) {
d.push_back(PIChar(str[i]));
}
return *this;
}
PIString & PIString::operator +=(const PIString & str) {
*((PIDeque<PIChar>*)this) << *((PIDeque<PIChar>*)&str);
d.append(str.d);
return *this;
}
PIString & PIString::operator +=(const PIConstChars & str) {
if (!str.isEmpty()) {
size_t os = d.size();
d.enlarge(str.size());
for (size_t l = 0; l < d.size(); ++l) {
d[os + l] = str[l];
}
}
return *this;
}
bool PIString::operator ==(const PIString & str) const {
uint l = str.size();
if (size() != l) return false;
for (uint i = 0; i < l; ++i)
if (str[i] != at(i))
return false;
return true;
return d == str.d;
}
bool PIString::operator !=(const PIString & str) const {
uint l = str.size();
if (size() != l) return true;
for (uint i = 0; i < l; ++i)
if (str[i] != at(i))
return true;
return false;
return d != str.d;
}
bool PIString::operator <(const PIString & str) const {
uint l = str.size();
size_t l = str.size();
if (size() < l) return true;
if (size() > l) return false;
for (uint i = 0; i < l; ++i) {
if (at(i) == str[i]) continue;
if (at(i) < str[i]) return true;
for (size_t i = 0; i < l; ++i) {
if (at(i) == str.at(i)) continue;
if (at(i) < str.at(i)) return true;
else return false;
}
return false;
@@ -543,18 +454,33 @@ bool PIString::operator <(const PIString & str) const {
bool PIString::operator >(const PIString & str) const {
uint l = str.size();
size_t l = str.size();
if (size() < l) return false;
if (size() > l) return true;
for (uint i = 0; i < l; ++i) {
if (at(i) == str[i]) continue;
if (at(i) < str[i]) return false;
for (size_t i = 0; i < l; ++i) {
if (at(i) == str.at(i)) continue;
if (at(i) < str.at(i)) return false;
else return true;
}
return false;
}
//! \~\details
//! \~english
//! If "len" < 0 then returns substring from symbol "start" to end.
//! \~russian
//! Если "len" < 0 тогда возвращается подстрока от символа "start" и до конца.
//! \~\code
//! 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"
//! piCout << s.mid(7, 1); // s = "7"
//! piCout << s.mid(7, 4); // s = "789"
//! \endcode
//! \~\sa \a left(), \a right()
PIString PIString::mid(const int start, const int len) const {
//PIString str;
int s = start, l = len;
@@ -564,16 +490,26 @@ PIString PIString::mid(const int start, const int len) const {
s = 0;
}
if (l < 0) {
return PIString(&(at(s)), size_s() - s);
return PIString(d.data(s), size_s() - s);
} else {
if (l > length() - s)
l = length() - s;
return PIString(&(at(s)), l);
if (l > length() - s) l = length() - s;
return PIString(d.data(s), l);
}
return PIString();
}
//! \~\details
//! \~\code
//! 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"
//! \endcode
//! \~\sa \a cutLeft(), \a cutRight()
PIString & PIString::cutMid(const int start, const int len) {
int s = start, l = len;
if (l == 0) return *this;
@@ -581,17 +517,26 @@ PIString & PIString::cutMid(const int start, const int len) {
l += s;
s = 0;
}
if (l < 0)
remove(s, size() - s);
else {
if (l > length() - s)
l = length() - s;
remove(s, l);
if (l < 0) {
d.remove(s, size() - s);
} else {
if (l > length() - s) l = length() - s;
d.remove(s, l);
}
return *this;
}
//! \~\details
//! \~english Remove spaces, tabulations, line feeds and null symbols:
//! \~russian Удаляет пробелы, табуляцию, переводы строк и нулевые символы:
//! \~ ' ', '\\n', '\\r', '\\t', '\\0'
//! \~\code
//! PIString s(" \t string \n");
//! s.trim();
//! piCout << s; // s = "string"
//! \endcode
//! \~\sa \a trimmed()
PIString & PIString::trim() {
int st = -1, fn = 0;
trimsubstr(st, fn);
@@ -613,18 +558,39 @@ PIString PIString::trimmed() const {
}
//! \~\details
//! \~\code
//! 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"
//! \endcode
//! \~\sa \a replaced(), \a replaceAll()
PIString & PIString::replace(int from, int count, const PIString & with) {
count = piMini(count, length() - from);
if (count == with.size_s())
memcpy(PIDeque<PIChar>::data(from), static_cast<PIDeque<PIChar>>(with).data(), count * sizeof(PIChar));
else {
remove(from, count);
PIDeque<PIChar>::insert(from, with);
if (count == with.size_s()) {
memcpy(d.data(from), with.d.data(), count * sizeof(PIChar));
} else {
d.remove(from, count);
d.insert(from, with.d);
}
return *this;
}
//! \~\details
//! \~english If "ok" is not null, it set to "true" if something was replaced
//! \~russian Если "ok" не null, то устанавливает в "true" если замена произведена
//! \~\code
//! 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
//! \endcode
//! \~\sa \a replaced(), \a replaceAll()
PIString & PIString::replace(const PIString & what, const PIString & with, bool * ok) {
if (what.isEmpty()) {
if (ok != 0) *ok = false;
@@ -637,10 +603,18 @@ PIString & PIString::replace(const PIString & what, const PIString & with, bool
}
//! \~\details
//! \~\code
//! PIString s("substrings");
//! s.replaceAll("s", "_");
//! piCout << s; // s = "_ub_tring_"
//! \endcode
//! \~\sa \a replace(), \a replaced(), \a replacedAll()
PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
if (what.isEmpty() || what == with) return *this;
if (with.isEmpty()) removeAll(what);
else {
if (with.isEmpty()) {
removeAll(what);
} else {
int l = what.length(), dl = with.length() - what.length();
for (int i = 0; i < length() - l + 1; ++i) {
bool match = true;
@@ -651,16 +625,22 @@ PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
}
}
if (!match) continue;
if (dl > 0) PIDeque<PIChar>::insert(i, PIDeque<PIChar>((size_t)dl));
if (dl < 0) PIDeque<PIChar>::remove(i, -dl);
memcpy(PIDeque<PIChar>::data(i), &(with.at(0)), with.length() * sizeof(PIChar));
//i -= l;
if (dl > 0) d.insert(i, PIDeque<PIChar>((size_t)dl));
if (dl < 0) d.remove(i, -dl);
memcpy(d.data(i), with.d.data(), with.size() * sizeof(PIChar));
}
}
return *this;
}
//! \~\details
//! \~\code
//! PIString s("substrings");
//! s.replaceAll("s", '_');
//! piCout << s; // s = "_ub_tring_"
//! \endcode
//! \~\sa \a replace(), \a replaced(), \a replacedAll()
PIString & PIString::replaceAll(const PIString & what, const char with) {
if (what.isEmpty()) return *this;
int l = what.length(), dl = what.length() - 1;
@@ -673,19 +653,24 @@ PIString & PIString::replaceAll(const PIString & what, const char with) {
}
}
if (!match) continue;
if (dl > 0) PIDeque<PIChar>::remove(i, dl);
(*this)[i] = PIChar(with);
//i -= l;
if (dl > 0) d.remove(i, dl);
d[i] = PIChar(with);
}
return *this;
}
//! \~\details
//! \~\code
//! PIString s("substrings");
//! s.replaceAll('s', '_');
//! piCout << s; // s = "_ub_tring_"
//! \endcode
//! \~\sa \a replace(), \a replaced(), \a replacedAll()
PIString & PIString::replaceAll(const char what, const char with) {
int l = length();
for (int i = 0; i < l; ++i) {
if (at(i) == what)
(*this)[i] = with;
if (at(i) == what) d[i] = with;
}
return *this;
}
@@ -697,13 +682,13 @@ PIString & PIString::removeAll(const PIString & str) {
for (int i = 0; i < length() - l + 1; ++i) {
bool match = true;
for (int j = 0; j < l; ++j) {
if (at(j + i) != str[j]) {
if (d.at(j + i) != str.at(j)) {
match = false;
break;
}
}
if (!match) continue;
PIDeque<PIChar>::remove(i, l);
d.remove(i, l);
i -= l;
}
return *this;
@@ -711,7 +696,7 @@ PIString & PIString::removeAll(const PIString & str) {
PIString & PIString::insert(int index, const PIString & str) {
PIDeque<PIChar>::insert(index, *((const PIDeque<PIChar>*)&str));
d.insert(index, str.d);
return *this;
}
@@ -726,8 +711,8 @@ PIString & PIString::elide(int size, float pos) {
pos = piClampf(pos, 0.f, 1.f);
int ns = size - 2;
int ls = piRoundf(ns * pos);
remove(ls, length() - ns);
insert(ls, s_dotdot);
d.remove(ls, length() - ns);
d.insert(ls, s_dotdot.d);
return *this;
}
@@ -747,73 +732,201 @@ PIStringList PIString::split(const PIString & delim) const {
}
//! \~\details
//! \~\code
//! PIString s("012345012345");
//! piCout << s.find('-'); // -1
//! piCout << s.find('3'); // 3
//! piCout << s.find('3', 4); // 9
//! piCout << s.find('3', 10); // -1
//! \endcode
//! \~\sa \a findAny(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int PIString::find(const char c, const int start) const {
for (int i = start; i < length(); ++i)
if (at(i) == c)
return i;
for (int i = start; i < length(); ++i) {
if (at(i) == c) return i;
}
return -1;
}
//! \~\details
//! \~\code
//! PIString s("012345012345");
//! piCout << s.find("-"); // -1
//! piCout << s.find("34"); // 3
//! piCout << s.find("3", 4); // 9
//! piCout << s.find("3", 10); // -1
//! \endcode
//! \~\sa \a findAny(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int PIString::find(const PIString & str, const int start) const {
int l = str.length();
for (int i = start; i < length() - l + 1; ++i)
if (mid(i, l) == str)
return i;
for (int i = start; i < length() - l + 1; ++i) {
if (mid(i, l) == str) return i;
}
return -1;
}
//! \~\details
//! \~\code
//! piCout << PIString("1.str").findAny(".,:"); // 1
//! piCout << PIString("1,str").findAny(".,:"); // 1
//! piCout << PIString("1:str").findAny(".,:"); // 1
//! \endcode
//! \~\sa \a find(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int PIString::findAny(const PIString & str, const int start) const {
for (int i = start; i < length(); ++i) {
if (str.contains(at(i))) return i;
}
return -1;
}
//! \~\details
//! \~\code
//! PIString s("012345012345");
//! piCout << s.findLast('-'); // -1
//! piCout << s.findLast('3'); // 9
//! piCout << s.findLast('3', 4); // 9
//! piCout << s.findLast('3', 10); // -1
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int PIString::findLast(const char c, const int start) const {
for (int i = length() - 1; i >= start; --i)
if (at(i) == c)
return i;
for (int i = length() - 1; i >= start; --i) {
if (at(i) == c) return i;
}
return -1;
}
int PIString::findLast(PIChar c, const int start) const
{
for (int i = length() - 1; i >= start; --i) {
if (at(i) == c) return i;
}
return -1;
}
//! \~\details
//! \~\code
//! PIString s("012345012345");
//! piCout << s.findLast("-"); // -1
//! piCout << s.findLast("34"); // 9
//! piCout << s.findLast("3", 4); // 9
//! piCout << s.findLast("3", 10); // -1
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int PIString::findLast(const PIString & str, const int start) const {
int l = str.length();
for (int i = length() - l; i >= start; --i)
if (mid(i, l) == str)
return i;
for (int i = length() - l; i >= start; --i) {
if (mid(i, l) == str) return i;
}
return -1;
}
//! \~\details
//! \~\code
//! piCout << PIString(".str.0").findAnyLast(".,:"); // 4
//! piCout << PIString(".str,0").findAnyLast(".,:"); // 4
//! piCout << PIString(".str:0").findAnyLast(".,:"); // 4
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findLast(), \a findWord(), \a findCWord(), \a findRange()
int PIString::findAnyLast(const PIString & str, const int start) const {
for (int i = length() - 1; i >= start; --i) {
if (str.contains(at(i))) return i;
}
return -1;
}
//! \~\details
//! \~\code
//! PIString s("this is <PIP>");
//! piCout << s.findWord("this"); // 0
//! piCout << s.findWord("is"); // 5
//! piCout << s.findWord("PIP", 4); // -1
//! piCout << s.findWord("<PIP>", 4); // 8
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findLast(), \a findAnyLast(), \a findCWord(), \a findRange()
int PIString::findWord(const PIString & word, const int start) const {
int f = start - 1, tl = length(), wl = word.length();
while ((f = find(word, f + 1)) >= 0) {
bool ok = true;
PIChar c;
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}}
if (f > 0) {
c = at(f - 1);
if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {
ok = false;
continue;
}
}
if (f + wl < tl) {
c = at(f + wl);
if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {
ok = false;
continue;
}
}
if (ok) return f;
}
return -1;
}
//! \~\details
//! \~\code
//! PIString s("this::is <PIP>");
//! piCout << s.findCWord("this"); // 0
//! piCout << s.findCWord("is"); // 6
//! piCout << s.findCWord("PIP", 4); // 10
//! piCout << s.findCWord("<PIP>", 4); // 9
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findLast(), \a findAnyLast(), \a findWord(), \a findRange()
int PIString::findCWord(const PIString & word, const int start) const {
int f = start - 1, tl = length(), wl = word.length();
while ((f = find(word, f + 1)) >= 0) {
bool ok = true;
PIChar c;
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}}
if (f > 0) {
c = at(f - 1);
if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {
ok = false;
continue;
}
}
if (f + wl < tl) {
c = at(f + wl);
if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {
ok = false;
continue;
}
}
if (ok) return f;
}
return -1;
}
//! \~\details
//! \~\code
//! PIString s(" {figures{inside}}");
//! int len = -1;
//! piCout << s.findRange('{', '}', '\\', 0, &len) << len << s.mid(2, len); // 2 15 figures{inside}
//! s = "\"text\\\"shielded\" next";
//! piCout << s.findRange('"', '"', '\\', 0, &len) << len << s.mid(1, len); // 1 14 text\"shielded
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord()
int PIString::findRange(const PIChar start, const PIChar end, const PIChar shield, const int start_index, int * len) const {
if (len) *len = 0;
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
int sz = size_s(), ls = -1, le = -1, cnt = 0;
for (int i = start_index; i < sz; ++i) {
PIChar c = at(i);
if (c == shield) {++i; continue;}
if (c == shield) {
++i;
continue;
}
if (trim_) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
@@ -844,26 +957,11 @@ int PIString::findRange(const PIChar start, const PIChar end, const PIChar shiel
}
int PIString::findAny(const PIString & str, const int start) const {
for (int i = start; i < length(); ++i)
if (str.contains(at(i)))
return i;
return -1;
}
int PIString::findAnyLast(const PIString & str, const int start) const {
for (int i = length() - 1; i >= start; --i)
if (str.contains(at(i)))
return i;
return -1;
}
int PIString::entries(const PIChar c) const {
int sz = size_s(), ret = 0;
for (int i = 0; i < sz; ++i)
for (int i = 0; i < sz; ++i) {
if (at(i) == c) ++ret;
}
return ret;
}
@@ -880,6 +978,17 @@ bool PIString::endsWith(const PIString & str) const {
}
//! \~\details
//! \~\code
//! piCout << PIString("true").toBool(); // true
//! piCout << PIString("Yes").toBool(); // true
//! piCout << PIString(" TRUE ").toBool(); // true
//! piCout << PIString(" 1 ").toBool(); // true
//! piCout << PIString("0").toBool(); // false
//! piCout << PIString("0.1").toBool(); // true
//! piCout << PIString("-1").toBool(); // false
//! piCout << PIString("").toBool(); // false
//! \endcode
bool PIString::toBool() const {
static const PIString s_true = PIStringAscii("true");
static const PIString s_yes = PIStringAscii("yes" );
@@ -893,13 +1002,21 @@ bool PIString::toBool() const {
}
//! \~\details
//! \~\code
//! PIString s("\t ! word");
//! piCout << s.takeSymbol(); // "!"
//! piCout << s.takeSymbol(); // "w"
//! piCout << s.takeSymbol(); // "o"
//! piCout << s; // "rd"
//! \endcode
//! \~\sa \a takeWord(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange()
PIString PIString::takeSymbol() {
PIString ret;
int sz = size_s(), ss = -1;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
ss = i;
break;
}
@@ -910,6 +1027,15 @@ PIString PIString::takeSymbol() {
}
//! \~\details
//! \~\code
//! PIString s("some words\nnew line ");
//! piCout << s.takeWord(); // "some"
//! piCout << s.takeWord(); // "words"
//! piCout << s.takeWord(); // "new"
//! piCout << s; // " line "
//! \endcode
//! \~\sa \a takeSymbol(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange()
PIString PIString::takeWord() {
int sz = size_s(), ws = -1, we = -1;
for (int i = 0; i < sz; ++i) {
@@ -930,6 +1056,10 @@ PIString PIString::takeWord() {
}
//! \~\details
//! \~\code
//! \endcode
//! \~\sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber(), \a takeRange()
PIString PIString::takeCWord() {
PIString ret;
int sz = size_s(), ws = -1, we = -1;
@@ -942,10 +1072,11 @@ PIString PIString::takeCWord() {
}
} else {
if (ws < 0) {
if (c.isAlpha() || c == '_')
if (c.isAlpha() || c == '_') {
ws = i;
else
} else {
return ret;
}
} else {
if (!c.isAlpha() && !c.isDigit() && c != '_') {
we = i;
@@ -961,6 +1092,15 @@ PIString PIString::takeCWord() {
}
//! \~\details
//! \~\code
//! PIString s("some words\nnew line \n\nend");
//! piCout << s.takeLine(); // "some words"
//! piCout << s.takeLine(); // "new line "
//! piCout << s.takeLine(); // ""
//! piCout << s; // "end"
//! \endcode
//! \~\sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeNumber(), \a takeRange()
PIString PIString::takeLine() {
int sz = size_s(), le = -1;
for (int i = 0; i < sz; ++i) {
@@ -971,14 +1111,26 @@ PIString PIString::takeLine() {
}
}
PIString ret = left(le);
if (!ret.isEmpty())
if (ret.back() == '\r')
if (!ret.isEmpty()) {
if (ret.back() == '\r') {
ret.cutRight(1);
}
}
cutLeft(le < 0 ? sz : le + 1);
return ret;
}
//! \~\details
//! \~\code
//! 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; // ""
//! \endcode
//! \~\sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeLine(), \a takeRange()
PIString PIString::takeNumber() {
PIString ret;
int sz = size_s(), ls = -1, le = -1, phase = 0;
@@ -988,37 +1140,75 @@ PIString PIString::takeNumber() {
//piCout << "char " << c << "phase" << phase;
switch (phase) {
case 0: // trim
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
continue;
}
phase = 7;
case 7: // sign
if (c == '-' || c == '+') {ls = i; phase = 1; break;}
if (c == '-' || c == '+') {
ls = i;
phase = 1;
break;
}
case 1: // search start
if (c >= '0' && c <= '9') {le = i; if (ls < 0) ls = i; phase = 2; break;}
if (c == '.') {le = i; if (ls < 0) ls = i; phase = 3; break;}
if ((c >= '0' && c <= '9') || c == '.') {
le = i;
if (ls < 0) ls = i;
if (c == '.') phase = 3;
else phase = 2;
break;
}
phase = 9;
break;
case 2: // integer
if (c == '.') {le = i; phase = 3; break;}
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') {le = i; break;}
if (c == '.') {
le = i;
phase = 3;
break;
}
if (c == 'e' || c == 'E') {
le = i;
phase = 4;
break;
}
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') {
le = i;
break;
}
phase = 6;
break;
case 3: // point
if (c == 'e' || c == 'E') {le = i; phase = 4; break;}
if (c >= '0' && c <= '9') {le = i; break;}
if (c == 'e' || c == 'E') {
le = i;
phase = 4;
break;
}
if (c >= '0' && c <= '9') {
le = i;
break;
}
phase = 6;
break;
case 4: // exp
if ((c >= '0' && c <= '9') || c == '-' || c == '+') {le = i; phase = 5; break;}
if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
le = i;
phase = 5;
break;
}
phase = 6;
break;
case 5: // power
if (c >= '0' && c <= '9') {le = i; break;}
if (c >= '0' && c <= '9') {
le = i;
break;
}
phase = 6;
break;
case 6: // suffix
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') {le = i; break;}
if (c == 'f' || c == 's' || c == 'u' || c == 'l' || c == 'L') {
le = i;
break;
}
phase = 9;
break;
}
@@ -1035,22 +1225,43 @@ PIString PIString::takeNumber() {
}
//! \~\details
//! \~english "shield" symbol prevent analysis of the next symbol
//! \~russian Символ "shield" экранирует следующий символ
//! \~\code
//! PIString s(" {figures{inside}}");
//! piCout << s.takeRange('{', '}'); // "figures{inside}"
//! piCout << s; // ""
//! s = "\"text\\\"shielded\" next";
//! piCout << s.takeRange('"', '"'); // "text\"shielded"
//! piCout << s; // " next"
//! \endcode
//! \~\sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber()
PIString PIString::takeRange(const PIChar start, const PIChar end, const PIChar shield) {
PIString ret;
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
int sz = size_s(), ls = -1, le = -1, cnt = 0;
for (int i = 0; i < sz; ++i) {
PIChar c = at(i);
if (c == shield) {++i; continue;}
if (c == shield) {
++i;
continue;
}
if (trim_) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
continue;
}
trim_ = false;
}
if (eq) {
if (c == start) {
if (cnt == 0) ls = i;
else {le = i; cnt = 0; break;}
if (cnt == 0) {
ls = i;
} else {
le = i;
cnt = 0;
break;
}
cnt++;
}
} else {
@@ -1073,6 +1284,12 @@ PIString PIString::takeRange(const PIChar start, const PIChar end, const PIChar
}
//! \~\details
//! \~\code
//! PIString s("a(b(c)d)e");
//! piCout << s.inBrackets('(', ')'); // "b(c)d"
//! piCout << s; // s = "a(b(c)d)e"
//! \endcode
PIString PIString::inBrackets(const PIChar start, const PIChar end) const {
int slen = length();
int st = -1, bcnt = 0;
@@ -1092,10 +1309,89 @@ PIString PIString::inBrackets(const PIChar start, const PIChar end) const {
}
//! \~\details
//! \~english
//! This function fill internal buffer by sequence of chars.
//! Length of this buffer is count of symbols + end byte '\0'.
//! Returned pointer is valid until next execution of this function.
//! \~russian
//! Этот метод заполняет внутренный байтовый буфер. Размер
//! этого буфера равен количеству символов строки + завершающий байт '\0'.
//! Возвращаемый указатель действителен до следующего вызова этого метода.
//! \~\code
//! piCout << PIString("0123456789").data(); // 0123456789
//! piCout << PIString("№1").data(); // №1
//! \endcode
//! \~\sa \a dataConsole(), \a dataUTF8()
const char * PIString::data() const {
if (isEmpty()) return "";
buildData(__syslocname__);
return data_;
}
//! \~\details
//! \~english
//! This function fill internal buffer by sequence of chars.
//! Length of this buffer is count of symbols + end byte '\0'.
//! Returned pointer is valid until next execution of this function.
//! \~russian
//! Этот метод заполняет внутренный байтовый буфер. Размер
//! этого буфера равен количеству символов строки + завершающий байт '\0'.
//! Возвращаемый указатель действителен до следующего вызова этого метода.
//! \~\sa \a data(), \a dataUTF8()
const char * PIString::dataConsole() const {
if (isEmpty()) return "";
buildData(__sysoemname__ );
return data_;
}
//! \~\details
//! \~english
//! This function fill internal buffer by sequence of chars.
//! Length of this buffer is count of symbols + end byte '\0'.
//! Returned pointer is valid until next execution of this function.
//! \~russian
//! Этот метод заполняет внутренный байтовый буфер. Размер
//! этого буфера равен количеству символов строки + завершающий байт '\0'.
//! Возвращаемый указатель действителен до следующего вызова этого метода.
//! \~\sa \a data(), \a dataConsole()
const char * PIString::dataUTF8() const {
if (isEmpty()) return "";
buildData(__utf8name__);
return data_;
}
//! \~\details
//! \~english
//! This function fill internal buffer by sequence of chars.
//! Length of this buffer is count of symbols + end byte '\0'.
//! Returned pointer is valid until next execution of this function.
//! \~russian
//! Этот метод заполняет внутренный байтовый буфер. Размер
//! этого буфера равен количеству символов строки + завершающий байт '\0'.
//! Возвращаемый указатель действителен до следующего вызова этого метода.
//! \~\sa \a dataConsole(), \a dataUTF8()
const char * PIString::dataAscii() const {
if (isEmpty()) return "";
deleteData();
data_ = (char*)malloc(size()+1);
for (int i = 0; i < size_s(); ++i) {
data_[i] = uchar(at(i).ch);
}
data_[size()] = '\0';
return data_;
}
PIString PIString::toUpperCase() const {
PIString str(*this);
int l = str.size();
for (int i = 0; i < l; ++i) str[i] = str[i].toUpper();
for (int i = 0; i < l; ++i) {
str.d[i] = str.d[i].toUpper();
}
return str;
}
@@ -1103,7 +1399,9 @@ PIString PIString::toUpperCase() const {
PIString PIString::toLowerCase() const {
PIString str(*this);
int l = str.size();
for (int i = 0; i < l; ++i) str[i] = str[i].toLower();
for (int i = 0; i < l; ++i) {
str.d[i] = str.d[i].toLower();
}
return str;
}
@@ -1142,25 +1440,60 @@ ldouble PIString::toLDouble() const {
}
//! \~\details
//! \~english
//! Example:
//! \~russian
//! Пример:
//! \~\code
//! 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
//! \endcode
PIString & PIString::setReadableSize(llong bytes) {
clear();
if (bytes < 1024) {*this += (PIString::fromNumber(bytes) + PIStringAscii(" B")); return *this;}
if (bytes < 1024) {
*this += (PIString::fromNumber(bytes) + PIStringAscii(" B"));
return *this;
}
double fres = bytes / 1024.;
llong res = bytes / 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" kB")); return *this;}
if (res < 1024) {
*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" kB"));
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" MB")); return *this;}
if (res < 1024) {
*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" MB"));
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" GB")); return *this;}
if (res < 1024) {
*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" GB"));
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
if (res < 1024) {*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" TB")); return *this;}
if (res < 1024) {
*this += (PIString::fromNumber(res) + PIStringAscii(".") + PIString::fromNumber(llong(fres * 10)).left(1) + PIStringAscii(" TB"));
return *this;
}
fres = res / 1024.;
res /= 1024;
fres -= res;
@@ -1183,11 +1516,11 @@ void parseVersion(PIString s, PIVector<int> & codes, PIStringList & strs) {
int ind = s.findLast('.') + 1;
while (!_versionDelims_.contains(s[ind])) {
++ind;
if (ind > s.size_s() - 1)
break;
if (ind > s.size_s() - 1) break;
}
for (int i = 0; i < mccnt; ++i)
for (int i = 0; i < mccnt; ++i) {
s.insert(ind, PIStringAscii(".0"));
}
}
PIStringList comps;
while (!s.isEmpty()) {
@@ -1201,8 +1534,7 @@ void parseVersion(PIString s, PIVector<int> & codes, PIStringList & strs) {
}
}
for (int i = 0; i < comps.size_s(); ++i) {
if (comps[i].isEmpty())
comps[i] = '0';
if (comps[i].isEmpty()) comps[i] = '0';
bool ok = false;
int val = comps[i].toInt(-1, &ok);
if (ok) {
@@ -1236,6 +1568,38 @@ int versionLabelValue(PIString s) {
}
//! \relatesalso PIString
//! \~\details
//! \~english
//! This function parse version to number codes and labels. Then it
//! compare no more than "components" codes. If there is no difference, compare
//! labels. Each label has corresponding integer value, so
//! "prealpha" < "alpha" < "prebeta" < "beta" < "rc[N]" < "" < "r[N]".
//! Example:
//! \~russian
//! Этот метод разбирает версии на числовые части и метку. Затем сравнивает
//! не более чем "components" частей. Если различий нет, то сравниваются
//! метки. Каждой метке соответствует своё значение так, что
//! "prealpha" < "alpha" < "prebeta" < "beta" < "rc[N]" < "" < "r[N]".
//! Пример:
//! \~\code
//! piCout << versionCompare("1.0.0_rc2-999", "1.0.1_rc2-999"); // -1, <
//! piCout << versionCompare("1.0.0", "0.9.2"); // 1, >
//! piCout << versionCompare("1.0.0_r1", "1.0.0"); // 1, >
//! piCout << versionCompare("1.0.0_r1", "1.0.0", 3); // 0, =
//! piCout << versionCompare("1.0.0_r2", "1.0.0", 3); // 0, =
//! piCout << versionCompare(".2-alpha", "0.2_alpha"); // 0, =
//! piCout << versionCompare("1_prebeta", "1.0_alpha"); // 1, >
//! \endcode
//! \~\return
//! \~english
//! * 0 - equal
//! * 1 - v0 > v1
//! * -1 - v0 < v1
//! \~russian
//! * 0 - равны
//! * 1 - v0 > v1
//! * -1 - v0 < v1
int versionCompare(const PIString & v0, const PIString & v1, int components) {
PIStringList strs[2]; PIVector<int> codes[2];
parseVersion(v0.toLowerCase(), codes[0], strs[0]);
@@ -1264,6 +1628,25 @@ int versionCompare(const PIString & v0, const PIString & v1, int components) {
}
//! \relatesalso PIString
//! \~\details
//! \~english
//! Parse version as described in \a versionCompare() and returns
//! classic view of codes and labels: major.minor.revision[-build][_label].
//! Example:
//! \~russian
//! Разбирает версию по описанию \a versionCompare() и возвращает
//! классическое представление версии и метки: major.minor.revision[-build][_label].
//! Пример:
//! \~\code
//! piCout << versionNormalize(""); // 0.0.0
//! piCout << versionNormalize("1"); // 1.0.0
//! piCout << versionNormalize("1.2"); // 1.2.0
//! piCout << versionNormalize("1.2.3"); // 1.2.3
//! piCout << versionNormalize("1.2+rc1.99"); // 1.2.99_rc1
//! piCout << versionNormalize("1.2-alpha"); // 1.2.0_alpha
//! piCout << versionNormalize("1..4_rc2-999"); // 1.0.4-999_rc2
//! \endcode
PIString versionNormalize(const PIString & v) {
PIStringList strs; PIVector<int> codes;
parseVersion(v.toLowerCase(), codes, strs);
@@ -1286,10 +1669,7 @@ PIString versionNormalize(const PIString & v) {
PICout operator <<(PICout s, const PIString & v) {
s.space();
s.quote();
s.setControl(0, true);
s << v.data();
s.restoreControl();
s.writePIString(v);
s.quote();
return s;
}

View File

@@ -1,7 +1,8 @@
/*! @file pistring.h
* @brief String
*
* This file declare string and string list classes
/*! \file pistring.h
* \ingroup Core
* \brief
* \~english String class
* \~russian Класс строки
*/
/*
PIP - Platform Independent Primitives
@@ -26,712 +27,1529 @@
#define PISTRING_H
#include "pibytearray.h"
#include "piconstchars.h"
#define PIStringAscii PIString::fromAscii
class PIStringList;
class PIP_EXPORT PIString: public PIDeque<PIChar>
class PIP_EXPORT PIString
{
friend PIByteArray & operator >>(PIByteArray & s, PIString & v);
friend PIByteArray & operator <<(PIByteArray & s, const PIString & v);
public:
//! Contructs an empty string
PIString(): PIDeque<PIChar>() {}
typedef PIDeque<PIChar>::iterator iterator;
typedef PIDeque<PIChar>::const_iterator const_iterator;
typedef PIDeque<PIChar>::reverse_iterator reverse_iterator;
typedef PIDeque<PIChar>::const_reverse_iterator const_reverse_iterator;
typedef PIChar value_type;
typedef PIChar* pointer;
typedef const PIChar* const_pointer;
typedef PIChar& reference;
typedef const PIChar& const_reference;
typedef size_t size_type;
//! \~english Contructs an empty string.
//! \~russian Создает пустую строку.
PIString() {}
//! \~english Value for elide at left.
//! \~russian Значение для пропуска слева.
static const float ElideLeft ;
//! \~english Value for elide at center.
//! \~russian Значение для пропуска в середине.
static const float ElideCenter;
//! \~english Value for elide at right.
//! \~russian Значение для пропуска справа.
static const float ElideRight ;
PIString & operator +=(const PIChar c) {push_back(c); return *this;}
PIString & operator +=(const char c) {push_back(PIChar(c)); return *this;}
PIString & operator +=(const PIChar & c) {d.push_back(c); return *this;}
PIString & operator +=(const char c) {d.push_back(PIChar(c)); return *this;}
PIString & operator +=(const char * str);
PIString & operator +=(const wchar_t * str);
PIString & operator +=(const PIByteArray & ba) {appendFromChars((const char * )ba.data(), ba.size_s(), __utf8name__); return *this;}
PIString & operator +=(const PIString & str);
PIString & operator +=(const PIConstChars & str);
PIString(const PIString & o): PIDeque<PIChar>(o) {}
//! \~english Contructs a copy of string.
//! \~russian Создает копию строки.
PIString(const PIString & o) {d = o.d;}
PIString(PIString && o): PIDeque<PIChar>(std::move(o)) {}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
PIString(PIString && o): d(std::move(o.d)) {piSwap(data_, o.data_);}
//! \~english Contructs string with single character "c".
//! \~russian Создает строку из одного символа "c".
PIString(const PIChar c) {*this += c;}
//! \~english Contructs string with single character "c".
//! \~russian Создает строку из одного символа "c".
PIString(const char c) {*this += PIChar(c);}
//! Contructs string with single symbol "c"
PIString(const PIChar c): PIDeque<PIChar>() {*this += c;}
PIString(const char c): PIDeque<PIChar>() {*this += PIChar(c);}
//! \~english Contructs string from C-string "str" (system codepage).
//! \~russian Создает строку из C-строки "str" (кодировка системы).
//! \~\details
//! \~english
//! "str" should be null-terminated\n
//! \~russian
//! "str" должна заканчиваться нулевым байтом\n
//! \~\code
//! PIString s("string");
//! \endcode
PIString(const char * str) {*this += str;}
/*! @brief Contructs string from c-string "str"
* \details "str" should be null-terminated\n
* Example: \snippet pistring.cpp PIString(char * ) */
PIString(const char * str): PIDeque<PIChar>() {*this += str;}
//! \~english Contructs string from \c wchar_t C-string "str".
//! \~russian Создает строку из \c wchar_t C-строки "str".
//! \~\details
//! \~english
//! "str" should be null-terminated
//! \~russian
//! "str" должна заканчиваться нулевым \c wchar_t
//! \~\code
//! PIString s(L"string");
//! \endcode
PIString(const wchar_t * str) {*this += str;}
//! \~english Contructs string from byte array "ba" (as UTF-8).
//! \~russian Создает строку из байтового массива "ba" (как UTF-8).
PIString(const PIByteArray & ba) {*this += ba;}
//! \~english Contructs string from "len" characters of buffer "str".
//! \~russian Создает строку из "len" символов массива "str".
PIString(const PIChar * str, const int len): d(str, size_t(len)) {}
//! \~english Contructs string from "len" characters of buffer "str" (system codepage).
//! \~russian Создает строку из "len" символов массива "str" (кодировка системы).
//! \~\details
//! \~\code
//! PIString s("string", 3); // s = "str"
//! \endcode
PIString(const char * str, const int len) {appendFromChars(str, len);}
//! \~english Contructs string as sequence of characters "c" of buffer with length "len".
//! \~russian Создает строку как последовательность длиной "len" символа "c".
//! \~\details
//! \~\code
//! PIString s(5, 'p'); // s = "ppppp"
//! \endcode
PIString(const int len, const char c) {for (int i = 0; i < len; ++i) d.push_back(PIChar(c));}
//! \~english Contructs string as sequence of characters "c" of buffer with length "len".
//! \~russian Создает строку как последовательность длиной "len" символа "c".
//! \~\details
//! \~\code
//! PIString s(5, "№"); // s = "№№№№№"
//! \endcode
PIString(const int len, const PIChar c) {for (int i = 0; i < len; ++i) d.push_back(c);}
PIString(const PIConstChars & c) {*this += c;}
/*! @brief Contructs string from \c wchar_t c-string "str"
* \details "str" should be null-terminated\n
* Example: \snippet pistring.cpp PIString(wchar_t * ) */
PIString(const wchar_t * str): PIDeque<PIChar>() {*this += str;}
~PIString();
//! Contructs string from byte array "ba"
PIString(const PIByteArray & ba): PIDeque<PIChar>() {*this += ba;}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
PIString & operator =(const PIString & o) {if (this == &o) return *this; d = o.d; return *this;}
//! @brief Contructs string from "len" characters of buffer "str"
PIString(const PIChar * str, const int len): PIDeque<PIChar>(str, size_t(len)) {}
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
PIString & operator =(PIString && o) {d.swap(o.d); piSwap(data_, o.data_); return *this;}
/*! @brief Contructs string from "len" characters of buffer "str"
* \details Example: \snippet pistring.cpp PIString(char * , int) */
PIString(const char * str, const int len): PIDeque<PIChar>() {appendFromChars(str, len);}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
PIString & operator =(const PIConstChars & o) {d.clear(); *this += o; return *this;}
/*! @brief Contructs string as sequence of characters "c" of buffer with length "len"
* \details Example: \snippet pistring.cpp PIString(int, char) */
PIString(const int len, const char c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(c);}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
PIString & operator =(const char * o) {d.clear(); *this += o; return *this;}
/*! @brief Contructs string as sequence of symbols "c" of buffer with length "len"
* \details Example: \snippet pistring.cpp PIString(int, PIChar) */
PIString(const int len, const PIChar c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(c);}
~PIString() {}
PIString & operator =(const PIString & o) {if (this == &o) return *this; clear(); *this += o; return *this;}
PIString & operator =(PIString && o) {swap(o); return *this;}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator ==(const PIString & str) const;
//! Compare operator
bool operator ==(const PIChar c) const {if (size_s() != 1) return false; return at(0) == c;}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator ==(const PIChar c) const {if (d.size() != 1) return false; return d.at(0) == c;}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator ==(const char * str) const {return *this == PIString(str);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator !=(const PIString & str) const;
//! Compare operator
bool operator !=(const PIChar c) const {if (size_s() != 1) return true; return at(0) != c;}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator !=(const PIChar c) const {if (d.size() != 1) return true; return d.at(0) != c;}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator !=(const char * str) const {return *this != PIString(str);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <(const PIString & str) const;
//! Compare operator
bool operator <(const PIChar c) const {if (size_s() != 1) return size_s() < 1; return at(0) < c;}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <(const PIChar c) const {if (d.size() != 1) return d.size() < 1; return d.at(0) < c;}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <(const char * str) const {return *this < PIString(str);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >(const PIString & str) const;
//! Compare operator
bool operator >(const PIChar c) const {if (size_s() != 1) return size_s() > 1; return at(0) > c;}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >(const PIChar c) const {if (d.size() != 1) return d.size() > 1; return d.at(0) > c;}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >(const char * str) const {return *this > PIString(str);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <=(const PIString & str) const {return !(*this > str);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <=(const PIChar c) const {return !(*this > c);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <=(const char * str) const {return *this <= PIString(str);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >=(const PIString & str) const {return !(*this < str);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >=(const PIChar c) const {return !(*this < c);}
//! Compare operator
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >=(const char * str) const {return *this >= PIString(str);}
/*! @brief Append string "str" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(PIString) */
//! \~english Append string "str" at the end of string.
//! \~russian Добавляет в конец строку "str".
//! \~\details
//! \~\code
//! PIString s("this"), s1(" is"), s2(" string");
//! s << s1 << s2; // s = "this is string"
//! \endcode
PIString & operator <<(const PIString & str) {*this += str; return *this;}
/*! @brief Append symbol "c" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(PIChar) */
PIString & operator <<(const PIChar c) {*this += c; return *this;}
//! \~english Append character "c" at the end of string.
//! \~russian Добавляет в конец символ "c".
//! \~\details
//! \~\code
//! PIString s("stri");
//! s << PIChar('n') << PIChar('g'); // s = "string"
//! \endcode
PIString & operator <<(const PIChar c) {d.append(c); return *this;}
/*! @brief Append symbol "c" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(PIChar) */
PIString & operator <<(const char c) {*this += PIChar(c); return *this;}
//! \~english Append character `c` at the end of string.
//! \~russian Добавляет в конец символ `c`.
//! \~\details
//! \~\code
//! PIString s("stri");
//! s << 'n' << 'g'; // s = "string"
//! \endcode
PIString & operator <<(const char c) {d.append(PIChar(c)); return *this;}
/*! @brief Append c-string "str" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(char * ) */
//! \~english Append С-string "str" at the end of string.
//! \~russian Добавляет в конец C-строку "str".
//! \~\details
//! \~\code
//! PIString s("this");
//! s << " is" << " string"; // s = "this is string"
//! \endcode
PIString & operator <<(const char * str) {*this += str; return *this;}
/*! @brief Append \c wchar_t c-string "str" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(wchar_t * ) */
//! \~english Append \c wchar_t C-string "str" at the end of string.
//! \~russian Добавляет в конец \c wchar_t C-строку "str".
//! \~\details
//! \~\code
//! PIString s;
//! s << L"№ -" << " number"; // s = "№ - number"
//! \endcode
PIString & operator <<(const wchar_t * str) {*this += str; return *this;}
/*! @brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
PIString & operator <<(const PIConstChars & str) {*this += str; return *this;}
//! \~english Append string representation of "num" at the end of string.
//! \~russian Добавляет в конец строковое представление "num".
//! \~\details
//! \~\code
//! PIString s("ten - ");
//! s << 10; // s = "ten - 10"
//! \endcode
PIString & operator <<(const int & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const uint & num) {*this += PIString::fromNumber(num); return *this;}
/*! @brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
//! \~english Append string representation of "num" at the end of string.
//! \~russian Добавляет в конец строковое представление "num".
//! \~\details
//! \~\code
//! PIString s("ten - ");
//! s << 10; // s = "ten - 10"
//! \endcode
PIString & operator <<(const long & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const ulong & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const llong & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const ullong & num) {*this += PIString::fromNumber(num); return *this;}
/*! @brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
//! \~english Append string representation of "num" at the end of string.
//! \~russian Добавляет в конец строковое представление "num".
//! \~\details
//! \~\code
//! PIString s("1/10 - ");
//! s << 0.1; // s = "1/10 - 0.1"
//! \endcode
PIString & operator <<(const float & num) {*this += PIString::fromNumber(num); return *this;}
/*! @brief Append string representation of "num" at the end of string
* \details Example: \snippet pistring.cpp PIString::<<(int) */
//! \~english Append string representation of "num" at the end of string.
//! \~russian Добавляет в конец строковое представление "num".
//! \~\details
//! \~\code
//! PIString s("1/10 - ");
//! s << 0.1; // s = "1/10 - 0.1"
//! \endcode
PIString & operator <<(const double & num) {*this += PIString::fromNumber(num); return *this;}
//! \~english Iterator to the first element.
//! \~russian Итератор на первый элемент.
//! \~\details
//! \~\return \ref stl_iterators
//! \~\sa \a end(), \a rbegin(), \a rend()
inline iterator begin() {return d.begin();}
//! \~english Iterator to the element following the last element.
//! \~russian Итератор на элемент, следующий за последним элементом.
//! \~\details
//! \~\return \ref stl_iterators
//! \~\sa \a begin(), \a rbegin(), \a rend()
inline iterator end() {return d.end();}
inline const_iterator begin() const {return d.begin();}
inline const_iterator end() const {return d.end();}
//! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
//! \~\details
//! \~english It corresponds to the last element of the non-reversed array.
//! \~russian Итератор для прохода массива в обратном порядке.
//! Указывает на последний элемент.
//! \~\return \ref stl_iterators
//! \~\sa \a rend(), \a begin(), \a end()
inline reverse_iterator rbegin() {return d.rbegin();}
//! \~english Returns a reverse iterator to the element.
//! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент, следующий за последним элементом.
//! \~\details
//! \~english It corresponds to the element preceding the first element of the non-reversed array.
//! \~russian Итератор для прохода массива в обратном порядке.
//! Указывает на элемент, предшествующий первому элементу.
//! \~\return \ref stl_iterators
//! \~\sa \a rbegin(), \a begin(), \a end()
inline reverse_iterator rend() {return d.rend();}
inline const_reverse_iterator rbegin() const {return d.rbegin();}
inline const_reverse_iterator rend() const {return d.rend();}
//! \~english Full access to character by `index`.
//! \~russian Полный доступ к символу по индексу `index`.
//! \~\details
//! \~english Сharacter index starts from `0`.
//! Сharacter index must be in range from `0` to `size()-1`.
//! Otherwise will be undefined behavior.
//! \~russian Индекс элемента считается от `0`.
//! Индекс символа должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline PIChar & operator [](size_t index) {return d[index];}
inline PIChar operator [](size_t index) const {return d[index];}
//! \~english Read only access to character by `index`.
//! \~russian Доступ исключительно на чтение к символу по индексу `index`.
//! \~\details
//! \~english Сharacter index starts from `0`.
//! Сharacter index must be in range from `0` to `size()-1`.
//! Otherwise will be undefined behavior.
//! \~russian Индекс символа считается от `0`.
//! Индекс символа должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline const PIChar at(size_t index) const {return d.at(index);}
//! \~english Returns the last character of the string.
//! \~russian Возвращает последний символ строки.
inline PIChar & back() {return d.back();}
inline PIChar back() const {return d.back();}
inline PIChar & front() {return d.front();}
inline PIChar front() const {return d.front();}
//! \~english Sets size of the string, new characters are copied from `c`.
//! \~russian Устанавливает размер строки, новые символы копируются из `c`.
//! \~\details
//! \~english If `new_size` is greater than the current \a size(),
//! characters are added to the end; the new characters are initialized from `c`.
//! If `new_size` is less than the current \a size(), characters are removed from the end.
//! \~russian Если `new_size` больше чем текущий размер строки \a size(),
//! новые символы добавляются в конец строки и создаются из `с`.
//! Если `new_size` меньше чем текущий размер строки \a size(),
//! лишние символы удаляются с конца строки.
//! \~\sa \a size(), \a clear()
inline PIString & resize(size_t new_size, PIChar c = PIChar()) {d.resize(new_size, c); return *this;}
//! \~english Delete one character at the end of string.
//! \~russian Удаляет один символ с конца строки.
inline PIString & pop_back() {d.pop_back(); return *this;}
//! \~english Delete one character at the benig of string.
//! \~russian Удаляет один символ с начала строки.
inline PIString & pop_front() {d.pop_front(); return *this;}
//! \~english Removes `count` characters from the string, starting at `index` position.
//! \~russian Удаляет символы из строки, начиная с позиции `index` в количестве `count`.
inline PIString & remove(size_t index, size_t count = 1) {d.remove(index, count); return *this;}
//! \~english Assigns character 'c' to all string characters.
//! \~russian Заполняет всю строку символами `c`.
inline PIString & fill(PIChar c = PIChar()) {d.fill(c); return *this;}
//! \~english Insert string "str" at the begin of string.
//! \~russian Вставляет "str" в начало строки.
PIString & prepend(const char * str) {insert(0, str); return *this;}
//! @brief Insert string "str" at the begin of string
PIString & prepend(const PIString & str) {insert(0, str); return *this;}
//! @brief Insert string "str" at the end of string
PIString & append(const PIString & str) {*this += str; return *this;}
//! \~english Insert string "str" at the begin of string.
//! \~russian Вставляет "str" в начало строки.
PIString & prepend(const PIString & str) {d.prepend(str.d); return *this;}
//! \~english Insert character `c` at the begin of string.
//! \~russian Вставляет символ `c` в начало строки.
PIString & prepend(const PIChar c) {d.prepend(c); return *this;}
//! \~english Insert character `c` at the begin of string.
//! \~russian Вставляет символ `c` в начало строки.
PIString & prepend(const char c) {d.prepend(PIChar(c)); return *this;}
//! \~english Insert string "str" at the begin of string.
//! \~russian Вставляет "str" в начало строки.
PIString & push_front(const char * str) {insert(0, str); return *this;}
//! \~english Insert string "str" at the begin of string.
//! \~russian Вставляет "str" в начало строки.
PIString & push_front(const PIString & str) {d.push_front(str.d); return *this;}
//! \~english Insert character `c` at the begin of string.
//! \~russian Вставляет символ `c` в начало строки.
PIString & push_front(const PIChar c) {d.push_front(c); return *this;}
//! \~english Insert character `c` at the begin of string.
//! \~russian Вставляет символ `c` в начало строки.
PIString & push_front(const char c) {d.push_front(PIChar(c)); return *this;}
//! \~english Insert string "str" at the end of string.
//! \~russian Вставляет "str" в конец строки.
PIString & append(const char * str) {*this += str; return *this;}
//! \~english Insert string "str" at the end of string.
//! \~russian Вставляет "str" в конец строки.
PIString & append(const PIString & str) {d.append(str.d); return *this;}
PIString & append(const PIConstChars & str) {*this += str; return *this;}
//! \~english Insert character `c` at the end of string.
//! \~russian Вставляет символ `c` в конец строки.
PIString & append(const PIChar c) {d.append(c); return *this;}
//! \~english Insert character `c` at the end of string.
//! \~russian Вставляет символ `c` в конец строки.
PIString & append(const char c) {d.append(PIChar(c)); return *this;}
//! \~english Insert string "str" at the end of string.
//! \~russian Вставляет "str" в конец строки.
PIString & push_back(const char * str) {*this += str; return *this;}
//! \~english Insert string "str" at the end of string.
//! \~russian Вставляет "str" в конец строки.
PIString & push_back(const PIString & str) {d.push_back(str.d); return *this;}
PIString & push_back(const PIConstChars & str) {*this += str; return *this;}
//! \~english Insert character `c` at the end of string.
//! \~russian Вставляет символ `c` в конец строки.
PIString & push_back(const PIChar c) {d.push_back(c); return *this;}
//! \~english Insert character `c` at the end of string.
//! \~russian Вставляет символ `c` в конец строки.
PIString & push_back(const char c) {d.push_back(PIChar(c)); return *this;}
/*! @brief Return part of string from symbol at index "start" and maximum length "len"
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::mid
* \sa \a left(), \a right() */
//! \~english Returns part of string from character at index "start" and maximum length "len".
//! \~russian Возвращает подстроку от символа "start" и максимальной длиной "len".
PIString mid(const int start, const int len = -1) const;
/*! @brief Return sub-string of string from symbol at index "start" and maximum length "len" */
//! \~english Synonym of \a mid().
//! \~russian Аналог \a mid().
PIString subString(const int start, const int len = -1) const {return mid(start, len);}
/*! @brief Return part of string from left and maximum length "len"
* \details Example: \snippet pistring.cpp PIString::left
* \sa \a mid(), \a right() */
//! \~english Returns part of string from start and maximum length "len".
//! \~russian Возвращает подстроку от начала и максимальной длиной "len".
//! \~\details
//! \~\code
//! 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"
//! \endcode
//! \~\sa \a mid(), \a right()
PIString left(const int len) const {return len <= 0 ? PIString() : mid(0, len);}
/*! @brief Return part of string from right and maximum length "len"
* \details Example: \snippet pistring.cpp PIString::right
* \sa \a mid(), \a left() */
//! \~english Returns part of string at end and maximum length "len".
//! \~russian Возвращает подстроку максимальной длиной "len" и до конца.
//! \~\details
//! \~\code
//! 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"
//! \endcode
//! \~\sa \a mid(), \a left()
PIString right(const int len) const {return len <= 0 ? PIString() : mid(size() - len, len);}
/*! @brief Remove part of string from symbol as index "start" and maximum length "len"
* and return this string
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::cutMid
* \sa \a cutLeft(), \a cutRight() */
//! \~english Remove part of string from character as index "start" and maximum length "len" and return this string.
//! \~russian Удаляет часть строки от символа "start" и максимальной длины "len", возвращает эту строку.
PIString & cutMid(const int start, const int len);
/*! @brief Remove part of string from left and maximum length "len" and return this string
* \details Example: \snippet pistring.cpp PIString::cutLeft
* \sa \a cutMid(), \a cutRight() */
//! \~english Remove part of string from start and maximum length "len" and return this string.
//! \~russian Удаляет часть строки от начала и максимальной длины "len", возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! s.cutLeft(1);
//! piCout << s; // s = "123456789"
//! s.cutLeft(3);
//! piCout << s; // s = "456789"
//! s.cutLeft(30);
//! piCout << s; // s = ""
//! \endcode
//! \~\sa \a cutMid(), \a cutRight()
PIString & cutLeft(const int len) {return len <= 0 ? *this : cutMid(0, len);}
/*! @brief Remove part of string from right and maximum length "len" and return this string
* \details Example: \snippet pistring.cpp PIString::cutRight
* \sa \a cutMid(), \a cutLeft() */
//! \~english Remove part of string at end and maximum length "len" and return this string.
//! \~russian Удаляет часть строки максимальной длины "len" от конца, возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! s.cutRight(1);
//! piCout << s; // s = "012345678"
//! s.cutRight(3);
//! piCout << s; // s = "012345"
//! s.cutRight(30);
//! piCout << s; // s = ""
//! \endcode
//! \~\sa \a cutMid(), \a cutLeft()
PIString & cutRight(const int len) {return len <= 0 ? *this : cutMid(size() - len, len);}
/*! @brief Remove spaces at the start and at the end of string and return this string
* \details Example: \snippet pistring.cpp PIString::trim
* \sa \a trimmed() */
//! \~english Remove spaces at the start and at the end of string and return this string.
//! \~russian Удаляет пробельные символы с начала и конца строки и возвращает эту строку.
PIString & trim();
/*! @brief Return copy of this string without spaces at the start and at the end
* \details Example: \snippet pistring.cpp PIString::trimmed
* \sa \a trim() */
//! \~english Returns copy of this string without spaces at the start and at the end.
//! \~russian Возвращает копию этой строки без пробельных символов с начала и конца.
//! \~\details
//! \~\code
//! PIString s(" \t string \n");
//! piCout << s.trimmed(); // s = "string"
//! piCout << s; // s = " string "
//! \endcode
//! \~\sa \a trim()
PIString trimmed() const;
/*! @brief Replace part of string from index "from" and maximum length "len"
* with string "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replace_0
* \sa \a replaced(), \a replaceAll() */
//! \~english Replace part of string from index "from" and maximum length "len" with string "with" and return this string.
//! \~russian Заменяет часть строки от символа "from" и максимальной длины "len" строкой "with", возвращает эту строку.
PIString & replace(const int from, const int count, const PIString & with);
/*! @brief Replace part copy of this string from index "from" and maximum length "len"
* with string "with" and return copied string
* \details Example: \snippet pistring.cpp PIString::replaced_0
* \sa \a replace(), \a replaceAll() */
//! \~english Replace part copy of this string from index "from" and maximum length "len" with string "with".
//! \~russian Заменяет часть копии этой строки от символа "from" и максимальной длины "len" строкой "with".
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! piCout << s.replaced(2, 3, "_cut_"); // s = "01_cut_56789"
//! piCout << s.replaced(0, 1, "one_"); // s = "one_123456789"
//! \endcode
//! \~\sa \a replace(), \a replaceAll()
PIString replaced(const int from, const int count, const PIString & with) const {PIString str(*this); str.replace(from, count, with); return str;}
/*! @brief Replace first founded substring "what" with string "with" and return this string
* \details If "ok" is not null, it set to "true" if something was replaced\n
* Example: \snippet pistring.cpp PIString::replace_1
* \sa \a replaced(), \a replaceAll() */
//! \~english Replace first founded substring "what" with string "with" and return this string.
//! \~russian Заменяет первую найденную подстроку "what" строкой "with", возвращает эту строку.
PIString & replace(const PIString & what, const PIString & with, bool * ok = 0);
/*! @brief Replace first founded substring "what" with string "with" and return copied string
* \details If "ok" is not null, it set to "true" if something was replaced\n
* Example: \snippet pistring.cpp PIString::replaced_1
* \sa \a replaced(), \a replaceAll() */
//! \~english Replace in string copy first founded substring "what" with string "with".
//! \~russian Заменяет в копии строки первую найденную подстроку "what" строкой "with".
//! \~\details
//! \~english If "ok" is not null, it set to "true" if something was replaced.
//! \~russian Если "ok" не null, то устанавливает в "true" если замена произведена.
//! \~\code
//! 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
//! \endcode
//! \~\sa \a replaced(), \a replaceAll()
PIString replaced(const PIString & what, const PIString & with, bool * ok = 0) const {PIString str(*this); str.replace(what, with, ok); return str;}
/*! @brief Replace all founded substrings "what" with strings "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replaceAll
* \sa \a replace(), \a replaced() */
//! \~english Replace all founded substrings "what" with strings "with" and return this string.
//! \~russian Заменяет все найденные подстроки "what" строками "with", возвращает эту строку.
PIString & replaceAll(const PIString & what, const PIString & with);
/*! @brief Replace all founded substrings "what" with symbol "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replaceAll
* \sa \a replace(), \a replaced() */
//! \~english Replace all founded substrings "what" with characters "with" and return this string.
//! \~russian Заменяет все найденные подстроки "what" символами "with", возвращает эту строку.
PIString & replaceAll(const PIString & what, const char with);
/*! @brief Replace all founded symbols "what" with symbol "with" and return this string
* \details Example: \snippet pistring.cpp PIString::replaceAll
* \sa \a replace(), \a replaced() */
//! \~english Replace all founded characters "what" with characters "with" and return this string.
//! \~russian Заменяет все найденные символы "what" символами "with", возвращает эту строку.
PIString & replaceAll(const char what, const char with);
//! \~english Replace all founded substrings "what" with strings "with" in string copy.
//! \~russian Заменяет в копии строки все найденные подстроки "what" строками "with".
//! \~\sa \a replaceAll()
PIString replacedAll(const PIString & what, const PIString & with) const {PIString str(*this); str.replaceAll(what, with); return str;}
//! \~english Replace all founded substrings "what" with characters "with" in string copy.
//! \~russian Заменяет в копии строки все найденные подстроки "what" символами "with".
//! \~\sa \a replaceAll()
PIString replacedAll(const PIString & what, const char with) const {PIString str(*this); str.replaceAll(what, with); return str;}
//! \~english Replace all founded characters "what" with characters "with" in string copy.
//! \~russian Заменяет в копии строки все найденные символы "what" символами "with".
//! \~\sa \a replaceAll()
PIString replacedAll(const char what, const char with) const {PIString str(*this); str.replaceAll(what, with); return str;}
//! \~english Remove all founded substrings "what" and return this string.
//! \~russian Удаляет все найденные подстроки "what", возвращает эту строку.
PIString & removeAll(const PIString & str);
PIString & removeAll(char c) {PIDeque<PIChar>::removeAll(PIChar(c)); return *this;}
//! \~english Remove all founded characters "what" and return this string.
//! \~russian Удаляет все найденные символы "what", возвращает эту строку.
PIString & removeAll(char c) {d.removeAll(PIChar(c)); return *this;}
/*! @brief Repeat content of string "times" times and return this string
* \details Example: \snippet pistring.cpp PIString::repeat */
//! \~english Repeat content of string "times" times and return this string.
//! \~russian Повторяет содержимое строки "times" раз и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s(" :-) ");
//! s.repeat(3);
//! piCout << s; // :-) :-) :-)
//! \endcode
//! \~\sa \a repeated()
PIString & repeat(int times) {PIString ss(*this); times--; piForTimes (times) *this += ss; return *this;}
/*! @brief Returns repeated "times" times string
* \details Example: \snippet pistring.cpp PIString::repeated */
//! \~english Returns repeated "times" times string.
//! \~russian Возвращает повторённую "times" раз строку.
//! \~\details
//! \~\code
//! PIString s(" :-) ");
//! piCout << s.repeated(3); // :-) :-) :-)
//! piCout << s; // :-)
//! \endcode
//! \~\sa \a repeat()
PIString repeated(int times) const {PIString ss(*this); return ss.repeat(times);}
/*! @brief Insert symbol "c" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_0 */
PIString & insert(const int index, const PIChar c) {PIDeque<PIChar>::insert(index, c); return *this;}
//! \~english Insert character "c" after index "index" and return this string.
//! \~russian Вставляет символ "c" после позиции "index" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("pp");
//! s.insert(1, "i");
//! piCout << s; // s = "pip"
//! \endcode
PIString & insert(const int index, const PIChar c) {d.insert(index, c); return *this;}
/*! @brief Insert symbol "c" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_1 */
//! \~english Insert character "c" after index "index" and return this string.
//! \~russian Вставляет символ "c" после позиции "index" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("pp");
//! s.insert(1, 'i');
//! piCout << s; // s = "pip"
//! \endcode
PIString & insert(const int index, const char c) {return insert(index, PIChar(c));}
/*! @brief Insert string "str" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_2 */
//! \~english Insert string "str" after index "index" and return this string.
//! \~russian Вставляет строку "str" после позиции "index" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("stg");
//! s.insert(2, "rin");
//! piCout << s; // s = "string"
//! \endcode
PIString & insert(const int index, const PIString & str);
/*! @brief Insert string "str" after index "index" and return this string
* \details Example: \snippet pistring.cpp PIString::insert_2 */
//! \~english Insert string "str" after index "index" and return this string.
//! \~russian Вставляет строку "str" после позиции "index" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("stg");
//! s.insert(2, "rin");
//! piCout << s; // s = "string"
//! \endcode
PIString & insert(const int index, const char * c) {return insert(index, PIString(c));}
/*! @brief Enlarge string to length "len" by addition sequence of symbols
* "c" at the end of string, and return this string
* \details Example: \snippet pistring.cpp PIString::expandRightTo
* \sa \a expandLeftTo() */
PIString & expandRightTo(const int len, const PIChar c) {if (len > length()) resize(len, c); return *this;}
//! \~english Enlarge string to length "len" by addition characters "c" at the end, and return this string.
//! \~russian Увеличивает длину строки до "len" добавлением символов "c" в конец и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("str");
//! s.expandRightTo(2, "_");
//! piCout << s; // s = "str"
//! s.expandRightTo(6, "_");
//! piCout << s; // s = "str___"
//! \endcode
//! \~\sa \a expandLeftTo(), \a expandedRightTo(), \a expandedLeftTo()
PIString & expandRightTo(const int len, const PIChar c) {if (len > d.size_s()) d.resize(len, c); return *this;}
/*! @brief Enlarge string to length "len" by addition sequence of symbols
* "c" at the beginning of string, and return this string
* \details Example: \snippet pistring.cpp PIString::expandLeftTo
* \sa \a expandRightTo() */
PIString & expandLeftTo(const int len, const PIChar c) {if (len > length()) insert(0, PIString(len - length(), c)); return *this;}
//! \~english Enlarge string to length "len" by addition characters "c" at the begin, and return this string.
//! \~russian Увеличивает длину строки до "len" добавлением символов "c" в начало и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("str");
//! s.expandLeftTo(2, "_");
//! piCout << s; // s = "str"
//! s.expandLeftTo(6, "_");
//! piCout << s; // s = "___str"
//! \endcode
//! \~\sa \a expandRightTo(), \a expandedRightTo(), \a expandedLeftTo()
PIString & expandLeftTo(const int len, const PIChar c) {if (len > d.size_s()) insert(0, PIString(len - d.size_s(), c)); return *this;}
/*! @brief Enlarge and returns copy of this string to length "len"
* by addition sequence of symbols "c" at the end of string
* \sa \a expandRightTo() */
//! \~english Enlarge copy of this string to length "len" by addition characters "c" at the end.
//! \~russian Увеличивает длину копии этой строки до "len" добавлением символов "c" в конец.
//! \~\details
//! \~\code
//! PIString s("str");
//! piCouy << s.expandedRightTo(5, "_"); // s = "str__"
//! piCout << s; // s = "str"
//! \endcode
//! \~\sa \a expandRightTo(), \a expandLeftTo(), \a expandedLeftTo()
PIString expandedRightTo(const int len, const PIChar c) const {return PIString(*this).expandRightTo(len, c);}
/*! @brief Enlarge and returns copy of this string to length "len"
* by addition sequence of symbols "c" at the beginning of string
* \sa \a expandLeftTo() */
//! \~english Enlarge copy of this string to length "len" by addition characters "c" at the begin.
//! \~russian Увеличивает длину копии этой строки до "len" добавлением символов "c" в начало.
//! \~\details
//! \~\code
//! PIString s("str");
//! piCouy << s.expandedLeftTo(5, "_"); // s = "__str"
//! piCout << s; // s = "str"
//! \endcode
//! \~\sa \a expandRightTo(), \a expandLeftTo(), \a expandedRightTo()
PIString expandedLeftTo(const int len, const PIChar c) const {return PIString(*this).expandLeftTo(len, c);}
/*! @brief Add "c" symbols at the beginning and end of the string, and return this string
* \sa \a quoted() */
PIString & quote(PIChar c = PIChar('"')) {insert(0, c); *this += c; return *this;}
//! \~english Add "c" characters at the beginning and end, and return this string.
//! \~russian Добавляет символ "c" в начало и конец и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("str");
//! s.quote();
//! piCout << s; // s = ""str""
//! \endcode
//! \~\sa \a quoted()
PIString & quote(PIChar c = PIChar('"')) {d.prepend(c); d.append(c); return *this;}
/*! @brief Return quoted copy of this string
* \sa \a quote() */
//! \~english Returns quoted copy of this string.
//! \~russian Возвращает копию строки с добавленным в начало и конец символом "c".
//! \~\details
//! \~\code
//! PIString s("str");
//! piCout << s.quoted(); // s = ""str""
//! piCout << s; // s = "str"
//! \endcode
//! \~\sa \a quote()
PIString quoted(PIChar c = PIChar('"')) {return PIString(*this).quote(c);}
/*! @brief Reverse string and return this string
* \details Example: \snippet pistring.cpp PIString::reverse
* \sa \a reversed() */
PIString & reverse() {PIString str(*this); clear(); piForeachCR (PIChar c, str) push_back(c); return *this;}
//! \~english Reverse string and return this string.
//! \~russian Разворачивает и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! s.reverse();
//! piCout << s; // s = "9876543210"
//! \endcode
//! \~\sa \a reversed()
PIString & reverse() {d.reverse(); return *this;}
/*! @brief Reverse copy of this string and return it
* \details Example: \snippet pistring.cpp PIString::reversed
* \sa \a reverse() */
PIString reversed() const {PIString str(*this); str.reverse(); return str;}
//! \~english Reverse copy of this string.
//! \~russian Разворачивает копию этой строки.
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! piCout << s.reversed(); // s = "9876543210"
//! piCout << s; // s = "0123456789"
//! \endcode
//! \~\sa \a reverse()
PIString reversed() const {PIString ret(*this); return ret.reverse();}
/*! @brief Elide string to maximum size \"size\" and return this string
* \sa \a elided() */
//! \~english Fit string to maximum size "size" by inserting ".." at position "pos" and return this string.
//! \~russian Уменьшает строку до размера "size", вставляя ".." в положение "pos" и возвращает эту строку.
//! \~\sa \a elided()
PIString & elide(int size, float pos = ElideCenter);
/*! @brief Elide copy of this string to maximum size \"size\" and return it
* \details Example: \snippet pistring.cpp PIString::elided
* \sa \a elide() */
//! \~english Fit copy of this string to maximum size "size" by inserting ".." at position "pos".
//! \~russian Уменьшает копию этой строки до размера "size", вставляя ".." в положение "pos".
//! \~\details
//! \~\code
//! 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
//! \endcode
//! \~\sa \a elide()
PIString elided(int size, float pos = ElideCenter) const {PIString str(*this); str.elide(size, pos); return str;}
/*! @brief Take a part of string from symbol at index "start" and maximum length "len" and return it
* \sa \a takeLeft, \a takeRight() */
//! \~english Take a part of string from character at index "start" and maximum length "len" and return it.
//! \~russian Извлекает часть строки от символа "start" максимальной длины "len" и возвращает её.
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! piCout << s.takeMid(1, 3); // "123"
//! piCout << s; // s = "0456789"
//! \endcode
//! \~\sa \a takeLeft, \a takeRight()
PIString takeMid(const int start, const int len = -1) {PIString ret(mid(start, len)); cutMid(start, len); return ret;}
/*! @brief Take a part from the begin of string with maximum length "len" and return it
* \sa \a takeMid(), \a takeRight() */
//! \~english Take a part from the begin of string with maximum length "len" and return it.
//! \~russian Извлекает часть строки от начала максимальной длины "len" и возвращает её.
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! piCout << s.takeLeft(3); // "012"
//! piCout << s; // s = "3456789"
//! \endcode
//! \~\sa \a takeMid(), \a takeRight()
PIString takeLeft(const int len) {PIString ret(left(len)); cutLeft(len); return ret;}
/*! @brief Take a part from the end of string with maximum length "len" and return it
* \sa \a takeMid(), \a takeLeft() */
//! \~english Take a part from the end of string with maximum length "len" and return it.
//! \~russian Извлекает часть строки с конца максимальной длины "len" и возвращает её.
//! \~\details
//! \~\code
//! PIString s("0123456789");
//! piCout << s.takeRight(3); // "789"
//! piCout << s; // s = "0123456"
//! \endcode
//! \~\sa \a takeMid(), \a takeLeft()
PIString takeRight(const int len) {PIString ret(right(len)); cutRight(len); return ret;}
/*! @brief Take a symbol from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeSymbol
* \sa \a takeWord(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
//! \~english Take a character from the begin of this string and return it.
//! \~russian Извлекает символ с начала строки и возвращает его как строку.
PIString takeSymbol();
/*! @brief Take a word from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeWord
* \sa \a takeSymbol(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
//! \~english Take a word from the begin of this string and return it.
//! \~russian Извлекает слово с начала строки и возвращает его.
PIString takeWord();
/*! @brief Take a word with letters, numbers and '_' symbols from the
* begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeCWord
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
//! \~english Take a word with letters, numbers and '_' characters from the begin of this string and return it.
//! \~russian Извлекает слово из букв, цифр и симолов '_' с начала строки и возвращает его.
PIString takeCWord();
/*! @brief Take a line from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeLine
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeNumber(), \a takeRange() */
//! \~english Take a line from the begin of this string and return it.
//! \~russian Извлекает строку текста (до новой строки) с начала строки и возвращает её.
PIString takeLine();
/*! @brief Take a number with C-format from the begin of this string and return it
* \details Example: \snippet pistring.cpp PIString::takeNumber
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeLine(), \a takeRange() */
//! \~english Take a number with C-format from the begin of this string and return it.
//! \~russian Извлекает число в C-формате с начала строки и возвращает его как строку.
PIString takeNumber();
/*! @brief Take a range between "start" and "end" symbols from the begin of this
* string and return it.
* \details "Shield" symbol prevent analysis of the next symbol.
* Example: \snippet pistring.cpp PIString::takeRange
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber() */
//! \~english Take a range between "start" and "end" characters from the begin of this string and return it.
//! \~russian Извлекает диапазон между символами "start" и "end" с начала строки и возвращает его.
PIString takeRange(const PIChar start, const PIChar end, const PIChar shield = '\\');
/*! @brief Return a string in brackets "start" and "end" symbols from the begin of this
* string and return it.
* \details Example: string = "a(b(c)d)e"; inBrackets('(', ')') = "b(c)d"; */
//! \~english Returns string in brackets "start" and "end" characters from the beginning.
//! \~russian Возвращает строку между символами "start" и "end" с начала строки.
PIString inBrackets(const PIChar start, const PIChar end) const;
/*! @brief Return real bytes count of this string
* \details It`s equivalent length of char sequence
* returned by function \a data() - 1, without terminating null-char \n
* Example: \snippet pistring.cpp PIString::lengthAscii
* \sa \a data() */
int lengthAscii() const {buildData(__syslocname__); return data_.size_s() - 1;}
//! \~english Returns \c char * representation of this string in system codepage.
//! \~russian Возвращает \c char * представление строки в системной кодировке.
const char * data() const;
/*! @brief Return \c char * representation of this string in system codepage
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n
* Example: \snippet pistring.cpp PIString::data
* \sa \a dataConsole(), \a dataUTF8() */
const char * data() const {buildData(__syslocname__); return (const char *)(data_.data());}
/*! @brief Return \c char * representation of this string in terminal codepage
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n
* \sa \a data(), \a dataUTF8() */
//! \~english Returns \c char * representation of this string in terminal codepage.
//! \~russian Возвращает \c char * представление строки в кодировке консоли.
const char * dataConsole() const;
/*! @brief Return \c char * representation of this string in UTF-8
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n
* \sa \a data(), \a dataConsole() */
//! \~english Returns \c char * representation of this string in UTF-8.
//! \~russian Возвращает \c char * представление строки в кодировке UTF-8.
const char * dataUTF8() const;
/*! @brief Return \c char * representation of this string in ASCII
* \details This function fill buffer by sequence
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n */
//! \~english Returns \c char * representation of this string in ASCII.
//! \~russian Возвращает \c char * представление строки в кодировке ASCII.
const char * dataAscii() const;
//! Returns hash
//! \~english Returns hash of string
//! \~russian Возвращает хэш строки
uint hash() const;
//! @brief Return \a PIByteArray contains \a data() of this string without terminating null-char
PIByteArray toByteArray() const {buildData(__utf8name__); return data_.resized(data_.size_s() - 1);}
//! \~english Same as \a toUTF8().
//! \~russian Тоже самое, что \a toUTF8().
PIByteArray toByteArray() const {return toUTF8();}
//! @brief Return \a PIByteArray contains UTF-8 \a data() of this string without terminating null-char
//! \~english Returns \a PIByteArray contains \a dataUTF8() of this string without terminating null-char.
//! \~russian Возвращает \a PIByteArray содержащий \a dataUTF8() строки без завершающего нулевого байта.
PIByteArray toUTF8() const;
//! @brief Return \a PIByteArray contains custom charset representation of this string without terminating null-char
//! \~english Returns \a PIByteArray contains custom charset representation of this string without terminating null-char.
//! \~russian Возвращает \a PIByteArray содержащий строку в указанной кодировке без завершающего нулевого байта.
PIByteArray toCharset(const char * c) const;
/*! @brief Split string with delimiter "delim" to \a PIStringList and return it
* \details Example: \snippet pistring.cpp PIString::split */
//! \~english Split string with delimiter "delim" to \a PIStringList.
//! \~russian Разделяет строку в \a PIStringList через разделитель "delim".
//! \~\details
//! \~\code
//! PIString s("1 2 3");
//! piCout << s.split(" "); // {"1", "2", "3"}
//! \endcode
PIStringList split(const PIString & delim) const;
//! @brief Convert each symbol in copyed string to upper case and return it
//! \~english Convert each character in copied string to upper case.
//! \~russian Преобразует каждый символ в скопированной строке в верхний регистр.
PIString toUpperCase() const;
//! @brief Convert each symbol in copyed string to lower case and return it
//! \~english Convert each character in copied string to lower case.
//! \~russian Преобразует каждый символ в скопированной строке в нижний регистр.
PIString toLowerCase() const;
// TODO: doxygen
PIString toNativeDecimalPoints() const;
//! @brief Returns if string contains "c"
bool contains(const char c) const {return PIDeque<PIChar>::contains(PIChar(c));}
//! \~english Returns if string contains character "c".
//! \~russian Возвращает содержит ли строка символ "c".
bool contains(const char c) const {return d.contains(PIChar(c));}
//! @brief Returns if string contains "str"
//! \~english Returns if string contains substring "str".
//! \~russian Возвращает содержит ли строка подстроку "str".
bool contains(const char * str) const {return contains(PIString(str));}
//! @brief Returns if string contains "str"
//! \~english Returns if string contains substring "str".
//! \~russian Возвращает содержит ли строка подстроку "str".
bool contains(const PIString & str) const {return find(str) >= 0;}
//! @brief Search symbol "c" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::find
//! \~english Search character "c" from character at index "start" and return first occur position.
//! \~russian Ищет символ "c" от символа "start" и возвращает первое вхождение.
int find(const char c, const int start = 0) const;
//! \~english Search character "c" from character at index "start" and return first occur position.
//! \~russian Ищет символ "c" от символа "start" и возвращает первое вхождение.
int find(PIChar c, const int start = 0) const {return d.indexOf(c, start);}
//! @brief Search substring "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::find
//! \~english Search substring "str" from character at index "start" and return first occur position.
//! \~russian Ищет подстроку "str" от символа "start" и возвращает первое вхождение.
int find(const PIString & str, const int start = 0) const;
//! @brief Search substring "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::find
//! \~english Search substring "str" from character at index "start" and return first occur position.
//! \~russian Ищет подстроку "str" от символа "start" и возвращает первое вхождение.
//! \~\details
//! \~\code
//! PIString s("012345012345");
//! piCout << s.find("-"); // -1
//! piCout << s.find("34"); // 3
//! piCout << s.find("3", 4); // 9
//! piCout << s.find("3", 10); // -1
//! \endcode
//! \~\sa \a findAny(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int find(const char * str, const int start = 0) const {return find(PIString(str), start);}
//! @brief Search symbol "c" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findLast
int findLast(const char c, const int start = 0) const;
//! @brief Search substring "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findLast
int findLast(const PIString & str, const int start = 0) const;
//! @brief Search substring "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findLast
int findLast(const char * str, const int start = 0) const {return findLast(PIString(str), start);}
//! @brief Search word "word" from symbol at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findWord
int findWord(const PIString & word, const int start = 0) const;
//! @brief Search C-style word "word" from symbol at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findCWord
int findCWord(const PIString & word, const int start = 0) const;
//! @brief Search range between "start" and "end" symbols at index "start_index" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findRange
int findRange(const PIChar start, const PIChar end, const PIChar shield = '\\', const int start_index = 0, int * len = 0) const;
//! @brief Search any symbol of "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::findAny
//! \~english Search any character of "str" from character at index "start" and return first occur position.
//! \~russian Ищет любой символ строки "str" от симола "start" и возвращает первое вхождение.
int findAny(const PIString & str, const int start = 0) const;
//! @brief Search any symbol of "str" from symbol at index "start" and return first occur position
//! \details Example: \snippet pistring.cpp PIString::findAny
//! \~english Search any character of "str" from character at index "start" and return first occur position.
//! \~russian Ищет любой символ строки "str" от симола "start" и возвращает первое вхождение.
//! \~\details
//! \~\code
//! piCout << PIString("1.str").findAny(".,:"); // 1
//! piCout << PIString("1,str").findAny(".,:"); // 1
//! piCout << PIString("1:str").findAny(".,:"); // 1
//! \endcode
//! \~\sa \a find(), \a findLast(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int findAny(const char * str, const int start = 0) const {return findAny(PIString(str), start);}
//! \~english Search character "c" from character at index "start" and return last occur position.
//! \~russian Ищет символ "c" от символа "start" и возвращает последнее вхождение.
int findLast(const char c, const int start = 0) const;
//! \~english Search character "c" from character at index "start" and return last occur position.
//! \~russian Ищет символ "c" от символа "start" и возвращает последнее вхождение.
int findLast(PIChar c, const int start = 0) const;
//! @brief Search any symbol of "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
//! \~english Search substring "str" from character at index "start" and return last occur position.
//! \~russian Ищет подстроку "str" от символа "start" и возвращает последнее вхождение.
int findLast(const PIString & str, const int start = 0) const;
//! \~english Search substring "str" from character at index "start" and return last occur position.
//! \~russian Ищет подстроку "str" от символа "start" и возвращает последнее вхождение.
//! \~\details
//! \~\code
//! PIString s("012345012345");
//! piCout << s.findLast("-"); // -1
//! piCout << s.findLast("34"); // 9
//! piCout << s.findLast("3", 4); // 9
//! piCout << s.findLast("3", 10); // -1
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findAnyLast(), \a findWord(), \a findCWord(), \a findRange()
int findLast(const char * str, const int start = 0) const {return findLast(PIString(str), start);}
//! \~english Search any character of "str" from character at index "start" and return last occur position.
//! \~russian Ищет любой символ строки "str" от символа "start" и возвращает последнее вхождение.
int findAnyLast(const PIString & str, const int start = 0) const;
//! @brief Search any symbol of "str" from symbol at index "start" and return last occur position
//! \details Example: \snippet pistring.cpp PIString::findAnyLast
//! \~english Search any character of "str" from character at index "start" and return last occur position.
//! \~russian Ищет любой символ строки "str" от символа "start" и возвращает последнее вхождение.
//! \~\details
//! \~\code
//! piCout << PIString(".str.0").findAnyLast(".,:"); // 4
//! piCout << PIString(".str,0").findAnyLast(".,:"); // 4
//! piCout << PIString(".str:0").findAnyLast(".,:"); // 4
//! \endcode
//! \~\sa \a find(), \a findAny(), \a findLast(), \a findWord(), \a findCWord(), \a findRange()
int findAnyLast(const char * str, const int start = 0) const {return findAnyLast(PIString(str), start);}
//! @brief Returns number of occurrences of symbol "c"
//! \~english Search word "word" from character at index "start" and return first occur position.
//! \~russian Ищет слово "word" от симола "start" и возвращает первое вхождение.
int findWord(const PIString & word, const int start = 0) const;
//! \~english Search C-word "word" from character at index "start" and return first occur position.
//! \~russian Ищет C-слово "word" от симола "start" и возвращает первое вхождение.
int findCWord(const PIString & word, const int start = 0) const;
//! \~english Search range start between "start" and "end" characters at index "start_index" and return first occur position.
//! \~russian Ищет начало диапазона между символами "start" и "end" от симола "start" и возвращает первое вхождение.
int findRange(const PIChar start, const PIChar end, const PIChar shield = '\\', const int start_index = 0, int * len = 0) const;
//! \~english Returns number of occurrences of character "c".
//! \~russian Возвращает число вхождений символа "c".
//! \~\details
//! \~\code
//! piCout << PIString(".str.0").entries("."); // 2
//! piCout << PIString(".str.0").entries("0"); // 1
//! \endcode
int entries(const PIChar c) const;
//! @brief Returns number of occurrences of symbol "c"
//! \~english Returns number of occurrences of character "c".
//! \~russian Возвращает число вхождений символа "c".
//! \~\details
//! \~\code
//! piCout << PIString(".str.0").entries('.'); // 2
//! piCout << PIString(".str.0").entries('0'); // 1
//! \endcode
int entries(char c) const {return entries(PIChar(c));}
//! @brief Return if string starts with "str"
//! \~english Returns if string starts with "str".
//! \~russian Возвращает начинается ли строка со "str".
bool startsWith(const PIString & str) const;
//! @brief Return if string ends with "str"
//! \~english Returns if string ends with "str".
//! \~russian Возвращает оканчивается ли строка на "str".
bool endsWith(const PIString & str) const;
//! @brief Return symbols length of string
int length() const {return size();}
//! @brief Return \c true if string is empty, i.e. length = 0
bool isEmpty() const {return (size() == 0 || *this == "");}
//! \~english Returns characters length of string.
//! \~russian Возвращает длину строки в символах.
int length() const {return d.size_s();}
//! \~english Returns characters length of string.
//! \~russian Возвращает длину строки в символах.
size_t size() const {return d.size();}
//! \~english Returns characters length of string.
//! \~russian Возвращает длину строки в символах.
ssize_t size_s() const {return d.size_s();}
//! @brief Return \c true if string equal "true", "yes", "on" or positive not null numeric value
//! \~english Returns \c true if string is empty, i.e. length = 0.
//! \~russian Возвращает \c true если строка пустая, т.е. длина = 0.
bool isEmpty() const {if (d.isEmpty()) return true; if (d.at(0) == PIChar()) return true; return false;}
//! \~english Returns \c true if string is not empty, i.e. length > 0.
//! \~russian Возвращает \c true если строка непустая, т.е. длина > 0.
bool isNotEmpty() const {return !isEmpty();}
//! \~english Clear string, will be empty string.
//! \~russian Очищает строку, строка становится пустой.
//! \~\details
//! \~\note
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
void clear() {d.clear();}
//! \~english Returns \c true if string equal "true", "yes", "on" or positive not null numeric value.
//! \~russian Возвращает \c true если строка равна "true", "yes", "on" или числу > 0.
bool toBool() const;
//! @brief Return \c char numeric value of string
//! \~english Returns \c char numeric value of string.
//! \~russian Возвращает \c char числовое значение строки.
char toChar() const;
//! @brief Return \c short numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c short numeric value of string in base "base".
//! \~russian Возвращает \c short числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toShort(); // 123
//! piCout << PIString("123").toShort(16); // 291
//! piCout << PIString("0x123").toShort(); // 291
//! piCout << PIString("1001").toShort(2); // 9
//! \endcode
short toShort(int base = -1, bool * ok = 0) const {return short(toNumberBase(*this, base, ok));}
//! @brief Return \c ushort numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c ushort numeric value of string in base "base".
//! \~russian Возвращает \c ushort числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toUShort(); // 123
//! piCout << PIString("123").toUShort(16); // 291
//! piCout << PIString("0x123").toUShort(); // 291
//! piCout << PIString("1001").toUShort(2); // 9
//! \endcode
ushort toUShort(int base = -1, bool * ok = 0) const {return ushort(toNumberBase(*this, base, ok));}
//! @brief Return \c int numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c int numeric value of string in base "base".
//! \~russian Возвращает \c int числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toInt(); // 123
//! piCout << PIString("123").toInt(16); // 291
//! piCout << PIString("0x123").toInt(); // 291
//! piCout << PIString("1001").toInt(2); // 9
//! \endcode
int toInt(int base = -1, bool * ok = 0) const {return int(toNumberBase(*this, base, ok));}
//! @brief Return \c uint numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c uint numeric value of string in base "base".
//! \~russian Возвращает \c uint числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toUInt(); // 123
//! piCout << PIString("123").toUInt(16); // 291
//! piCout << PIString("0x123").toUInt(); // 291
//! piCout << PIString("1001").toUInt(2); // 9
//! \endcode
uint toUInt(int base = -1, bool * ok = 0) const {return uint(toNumberBase(*this, base, ok));}
//! @brief Return \c long numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c long numeric value of string in base "base".
//! \~russian Возвращает \c long числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toLong(); // 123
//! piCout << PIString("123").toLong(16); // 291
//! piCout << PIString("0x123").toLong(); // 291
//! piCout << PIString("1001").toLong(2); // 9
//! \endcode
long toLong(int base = -1, bool * ok = 0) const {return long(toNumberBase(*this, base, ok));}
//! @brief Return \c ulong numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c ulong numeric value of string in base "base".
//! \~russian Возвращает \c ulong числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toULong(); // 123
//! piCout << PIString("123").toULong(16); // 291
//! piCout << PIString("0x123").toULong(); // 291
//! piCout << PIString("1001").toULong(2); // 9
//! \endcode
ulong toULong(int base = -1, bool * ok = 0) const {return ulong(toNumberBase(*this, base, ok));}
//! @brief Return \c llong numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c llong numeric value of string in base "base".
//! \~russian Возвращает \c llong числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toLLong(); // 123
//! piCout << PIString("123").toLLong(16); // 291
//! piCout << PIString("0x123").toLLong(); // 291
//! piCout << PIString("1001").toLLong(2); // 9
//! \endcode
llong toLLong(int base = -1, bool * ok = 0) const {return toNumberBase(*this, base, ok);}
//! @brief Return \c ullong numeric value of string in base "base"
//! \details Example: \snippet pistring.cpp PIString::toNumber
//! \~english Returns \c ullong numeric value of string in base "base".
//! \~russian Возвращает \c ullong числовое значение строки по основанию "base".
//! \~\details
//! \~english If "base" < 0 then base automatically select 16 if string start with "0x", therwise 10.
//! \~russian Если "base" < 0 тогда основание автоматически принимается 16 если строка начинается с "0x", иначе 10.
//! \~\code
//! piCout << PIString("123").toULLong(); // 123
//! piCout << PIString("123").toULLong(16); // 291
//! piCout << PIString("0x123").toULLong(); // 291
//! piCout << PIString("1001").toULLong(2); // 9
//! \endcode
ullong toULLong(int base = -1, bool * ok = 0) const {return ullong(toNumberBase(*this, base, ok));}
//! @brief Return \c float numeric value of string
//! \details Example: \snippet pistring.cpp PIString::toFloat
//! \~english Returns \c float numeric value of string.
//! \~russian Возвращает \c float числовое значение строки.
//! \~\details
//! \~\code
//! piCout << PIString("123").toFloat(); // 123
//! piCout << PIString("1.2E+2").toFloat(); // 120
//! piCout << PIString("0.01").toFloat(); // 0.01
//! \endcode
float toFloat() const;
//! @brief Return \c double numeric value of string
//! \details Example: \snippet pistring.cpp PIString::toFloat
//! \~english Returns \c double numeric value of string.
//! \~russian Возвращает \c double числовое значение строки.
//! \~\details
//! \~\code
//! piCout << PIString("123").toDouble(); // 123
//! piCout << PIString("1.2E+2").toDouble(); // 120
//! piCout << PIString("0.01").toDouble(); // 0.01
//! \endcode
double toDouble() const;
//! @brief Return \c ldouble numeric value of string
//! \details Example: \snippet pistring.cpp PIString::toFloat
//! \~english Returns \c ldouble numeric value of string.
//! \~russian Возвращает \c ldouble числовое значение строки.
//! \~\details
//! \~\code
//! piCout << PIString("123").toLDouble(); // 123
//! piCout << PIString("1.2E+2").toLDouble(); // 120
//! piCout << PIString("0.01").toLDouble(); // 0.01
//! \endcode
ldouble toLDouble() const;
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const short value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const short value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const ushort value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const ushort value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const int value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const int value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const uint value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const uint value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const long value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const long value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const ulong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const ulong value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const llong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const llong & value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::setNumber
PIString & setNumber(const ullong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;}
//! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(123);
//! piCout << s; // 123
//! s.setNumber(123, 16);
//! piCout << s; // 7B
//! \endcode
PIString & setNumber(const ullong & value, int base = 10, bool * ok = 0) {*this = PIString::fromNumber(value, base, ok); return *this;}
//! @brief Set string content to numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::setFloat
PIString & setNumber(const float value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
//! \~english Set string content to text representation of "value" with format "format" and precision "precision" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" в формате "format" и точностью "precision" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(12.3);
//! piCout << s; // 12.30000000
//! s.setNumber(12.3, 'f', 3);
//! piCout << s; // 12.300
//! s.setNumber(12.123456, 'f', 3);
//! piCout << s; // 12.123
//! s.setNumber(123456789., 'g', 2);
//! piCout << s; // 1.2e+08
//! s.setNumber(123456789., 'f', 0);
//! piCout << s; // 123456789
//! \endcode
PIString & setNumber(const float value, char format = 'f', int precision = 8) {*this = PIString::fromNumber(value, format, precision); return *this;}
//! @brief Set string content to numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::setFloat
PIString & setNumber(const double & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
//! \~english Set string content to text representation of "value" with format "format" and precision "precision" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" в формате "format" и точностью "precision" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(12.3);
//! piCout << s; // 12.30000000
//! s.setNumber(12.3, 'f', 3);
//! piCout << s; // 12.300
//! s.setNumber(12.123456, 'f', 3);
//! piCout << s; // 12.123
//! s.setNumber(123456789., 'g', 2);
//! piCout << s; // 1.2e+08
//! s.setNumber(123456789., 'f', 0);
//! piCout << s; // 123456789
//! \endcode
PIString & setNumber(const double & value, char format = 'f', int precision = 8) {*this = PIString::fromNumber(value, format, precision); return *this;}
//! @brief Set string content to numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::setFloat
PIString & setNumber(const ldouble & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;}
//! \~english Set string content to text representation of "value" with format "format" and precision "precision" and return this string.
//! \~russian Устанавливает содержимое строки в текстовое представление "value" в формате "format" и точностью "precision" и возвращает эту строку.
//! \~\details
//! \~\code
//! PIString s;
//! s.setNumber(12.3);
//! piCout << s; // 12.30000000
//! s.setNumber(12.3, 'f', 3);
//! piCout << s; // 12.300
//! s.setNumber(12.123456, 'f', 3);
//! piCout << s; // 12.123
//! s.setNumber(123456789., 'g', 2);
//! piCout << s; // 1.2e+08
//! s.setNumber(123456789., 'f', 0);
//! piCout << s; // 123456789
//! \endcode
PIString & setNumber(const ldouble & value, char format = 'f', int precision = 8) {*this = PIString::fromNumber(value, format, precision); return *this;}
//! @brief Set string content to human readable size in B/kB/MB/GB/TB
//! \details Example: \snippet pistring.cpp PIString::setReadableSize
//! \~english Set string content to human readable size in B/kB/MB/GB/TB/PB.
//! \~russian Устанавливает содержимое в строку с читаемым размером B/kB/MB/GB/TB/PB.
//! \~\sa PIString::readableSize()
PIString & setReadableSize(llong bytes);
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const short value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const ushort value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const int value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const uint value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const long value, int base = 10, bool * ok = 0) {return fromNumberBaseS(llong(value), base, ok);}
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const ulong value, int base = 10, bool * ok = 0) {return fromNumberBaseU(ullong(value), base, ok);}
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const llong & value, int base = 10, bool * ok = 0) {return fromNumberBaseS(value, base, ok);}
//! @brief Return string contains numeric representation of "value" in base "base"
//! \details Example: \snippet pistring.cpp PIString::fromNumber
//! \~english Returns string contains numeric representation of "value" in base "base".
//! \~russian Возвращает строковое представление числа "value" по основанию "base".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(123); // 123
//! piCout << PIString::fromNumber(123, 16); // 7B
//! \endcode
static PIString fromNumber(const ullong & value, int base = 10, bool * ok = 0) {return fromNumberBaseU(value, base, ok);}
//! @brief Return string contains numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::fromFloat
static PIString fromNumber(const float value, char format = 'f', int precision = 8) {return ftos(value, format, precision);}
//! \~english Returns string contains numeric representation of "value" with format "format" and precision "precision".
//! \~russian Возвращает строковое представление числа "value" в формате "format" и точностью "precision".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(12.3); // 12.30000000
//! piCout << PIString::fromNumber(12.3, 'f', 3); // 12.300
//! piCout << PIString::fromNumber(12.123456, 'f', 3); // 12.123
//! piCout << PIString::fromNumber(123456789., 'g', 2); // 1.2e+08
//! piCout << PIString::fromNumber(123456789., 'f', 0); // 123456789
//! \endcode
static PIString fromNumber(const float value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
//! @brief Return string contains numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::fromFloat
//! \~english Returns string contains numeric representation of "value" with format "format" and precision "precision".
//! \~russian Возвращает строковое представление числа "value" в формате "format" и точностью "precision".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(12.3); // 12.30000000
//! piCout << PIString::fromNumber(12.3, 'f', 3); // 12.300
//! piCout << PIString::fromNumber(12.123456, 'f', 3); // 12.123
//! piCout << PIString::fromNumber(123456789., 'g', 2); // 1.2e+08
//! piCout << PIString::fromNumber(123456789., 'f', 0); // 123456789
//! \endcode
static PIString fromNumber(const double & value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
//! @brief Return string contains numeric representation of "value"
//! \details Example: \snippet pistring.cpp PIString::fromFloat
//! \~english Returns string contains numeric representation of "value" with format "format" and precision "precision".
//! \~russian Возвращает строковое представление числа "value" в формате "format" и точностью "precision".
//! \~\details
//! \~\code
//! piCout << PIString::fromNumber(12.3); // 12.30000000
//! piCout << PIString::fromNumber(12.3, 'f', 3); // 12.300
//! piCout << PIString::fromNumber(12.123456, 'f', 3); // 12.123
//! piCout << PIString::fromNumber(123456789., 'g', 2); // 1.2e+08
//! piCout << PIString::fromNumber(123456789., 'f', 0); // 123456789
//! \endcode
static PIString fromNumber(const ldouble & value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
//! @brief Return "true" or "false"
static PIString fromBool(const bool value) {return PIString(value ? "true" : "false");}
//! \~english Returns "true" or "false"
//! \~russian Возвращает "true" или "false"
static PIString fromBool(const bool value) {return PIString(value ? PIStringAscii("true") : PIStringAscii("false"));}
//! @brief Return string constructed from terminal codepage
//! \~english Returns string constructed from terminal codepage.
//! \~russian Возвращает строку созданную из кодировки консоли.
static PIString fromConsole(const char * s);
//! @brief Return string constructed from system codepage
//! \~english Returns string constructed from system codepage.
//! \~russian Возвращает строку созданную из кодировки системы.
static PIString fromSystem(const char * s);
//! @brief Return string constructed from UTF-8
//! \~english Returns string constructed from UTF-8.
//! \~russian Возвращает строку созданную из UTF-8.
static PIString fromUTF8(const char * s);
//! @brief Return string constructed from UTF-8
static PIString fromUTF8(const PIByteArray &ba);
//! \~english Returns string constructed from UTF-8.
//! \~russian Возвращает строку созданную из UTF-8.
static PIString fromUTF8(const PIByteArray & utf);
//! @brief Return string constructed from ASCII
//! \~english Returns string constructed from ASCII.
//! \~russian Возвращает строку созданную из ASCII.
static PIString fromAscii(const char * s);
//! @brief Return string constructed from "len" chars ASCII
//! \~english Returns string constructed from "len" chars ASCII.
//! \~russian Возвращает строку созданную из "len" символов ASCII.
static PIString fromAscii(const char * s, int len);
//! @brief Return string constructed from "c" codepage
static PIString fromCodepage(const char * s, const char * c);
//! \~english Returns string constructed from "cp" codepage.
//! \~russian Возвращает строку созданную из кодировки "cp".
static PIString fromCodepage(const char * s, const char * cp);
//! @brief Return string contains human readable size in B/kB/MB/GB/TB
//! \details Example: \snippet pistring.cpp PIString::readableSize
//! \~english Returns string contains human readable size in B/kB/MB/GB/TB/PB.
//! \~russian Возвращает строку с читаемым размером B/kB/MB/GB/TB/PB.
//! \~\sa PIString::setReadableSize()
static PIString readableSize(llong bytes);
//! \~english Swaps string `str` other with this string.
//! \~russian Меняет строку `str` с этой строкой.
//! \~\details
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
void swap(PIString & str) {
d.swap(str.d);
piSwap(data_, str.data_);
}
private:
static const char toBaseN[];
static const int fromBaseN[];
static const char fromBaseN[];
static PIString itos(const int num);
static PIString ltos(const long num);
@@ -739,52 +1557,72 @@ private:
static PIString uitos(const uint num);
static PIString ultos(const ulong num);
static PIString ulltos(const ullong num);
static PIString ftos(const float num, char format = 'f', int precision = 8);
static PIString dtos(const double num, char format = 'f', int precision = 8);
static PIString fromNumberBaseS(const llong value, int base = 10, bool * ok = 0);
static PIString fromNumberBaseU(const ullong value, int base = 10, bool * ok = 0);
static llong toNumberBase(const PIString & value, int base = -1, bool * ok = 0);
void appendFromChars(const char * c, int s, const char * cp = __syslocname__);
void buildData(const char * cp = __syslocname__) const;
void deleteData() const;
void trimsubstr(int &st, int &fn) const;
mutable PIByteArray data_;
PIDeque<PIChar> d;
mutable char * data_ = nullptr;
};
//! \relatesalso PICout @brief Output operator to PICout
//! \relatesalso PICout
//! \~english Output operator to \a PICout.
//! \~russian Оператор вывода в \a PICout.
PIP_EXPORT PICout operator <<(PICout s, const PIString & v);
//! \relatesalso PIByteArray
//! \~english Store operator.
//! \~russian Оператор сохранения.
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << v.d; return s;}
//! \relatesalso PIByteArray @brief Output operator to PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << *(PIDeque<PIChar>*)&v; return s;}
//! \relatesalso PIByteArray @brief Input operator from PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {v.clear(); s >> *(PIDeque<PIChar>*)&v; return s;}
//! \relatesalso PIByteArray
//! \~english Restore operator.
//! \~russian Оператор извлечения.
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {v.d.clear(); s >> v.d; return s;}
//! @brief Return concatenated string
//! \~english Returns concatenated string.
//! \~russian Возвращает соединение строк.
inline PIString operator +(const PIString & str, const PIString & f) {PIString s(str); s += f; return s;}
//! @brief Return concatenated string
//! \~english Returns concatenated string.
//! \~russian Возвращает соединение строк.
inline PIString operator +(const PIString & f, const char * str) {PIString s(f); s += str; return s;}
//! @brief Return concatenated string
//! \~english Returns concatenated string.
//! \~russian Возвращает соединение строк.
inline PIString operator +(const char * str, const PIString & f) {return PIString(str) + f;}
//! \relatesalso PIString @brief Return concatenated string
//! \~english Returns concatenated string.
//! \~russian Возвращает соединение строк.
inline PIString operator +(const char c, const PIString & f) {return PIChar(c) + f;}
//! @brief Return concatenated string
//! \~english Returns concatenated string.
//! \~russian Возвращает соединение строк.
inline PIString operator +(const PIString & f, const char c) {return f + PIChar(c);}
//! \relatesalso PIString
//! \~english Compare two version strings in free notation and returns 0, -1 or 1.
//! \~russian Сравнивает две строки с версиями в произвольной форме и возвращает 0, -1 или 1.
int PIP_EXPORT versionCompare(const PIString & v0, const PIString & v1, int components = 6);
//! \relatesalso PIString
//! \~english Converts version string in free notation to classic view.
//! \~russian Преобразует строку с версией в произвольной форме к классическому виду.
PIString PIP_EXPORT versionNormalize(const PIString & v);
template<> inline uint piHash(const PIString & s) {return s.hash();}
template<> inline void piSwap(PIString & f, PIString & s) {f.swap(s);}
template<> inline void piSwap(PIString & f, PIString & s) {
f.swap(s);
}
#endif // PISTRING_H

View File

@@ -1,7 +1,8 @@
/*! @file pistring_std.h
* @brief STD for PIString
*
* This file declare std operators and string conversions
/*! \file pistring_std.h
* \ingroup Core
* \brief
* \~english STD convertions for PIString
* \~russian Преобразования в/из STD для строки
*/
/*
PIP - Platform Independent Primitives
@@ -34,13 +35,13 @@
inline std::string PIString2StdString(const PIString & v) {
std::string s;
uint wc;
ushort wc;
uchar tc;
if (v.size() > 0) {
for (int i = 0; i < v.length(); ++i) {
wc = uint(v.at(i).unicode16Code());
wc = v[i].unicode16Code();
while (tc = wc & 0xFF, tc) {
s.push_back(char(tc));
s.push_back(tc);
wc >>= 8;
}
}
@@ -48,46 +49,74 @@ inline std::string PIString2StdString(const PIString & v) {
return s;
}
inline PIString StdString2PIString(const std::string & v) {
return PIString(v.c_str(), v.length());
}
#ifdef HAS_LOCALE
inline std::wstring PIString2StdWString(const PIString & v) {
std::wstring s;
for (int i = 0; i < v.length(); ++i)
s.push_back(v.at(i).toWChar());
for (int i = 0; i < v.length(); ++i) {
s.push_back(v[i].toWChar());
}
return s;
}
inline PIString StdWString2PIString(const std::wstring & v) {
PIString s;
uint l = v.size();
for (uint i = 0; i < l; ++i) s.push_back(v[i]);
for (uint i = 0; i < l; ++i) {
s.push_back(PIChar(v[i]));
}
return s;
}
#endif
//! \relatesalso PIChar @brief Output operator to \c std::ostream
inline std::ostream & operator <<(std::ostream & s, const PIChar & v) {s << v.toCharPtr(); return s;}
//! \relatesalso PIString @brief Return concatenated string
inline PIString operator +(const PIString & f, const std::string & str) {PIString s(f); s += StdString2PIString(str); return s;}
//! \relatesalso PIString @brief Return concatenated string
inline PIString operator +(const std::string & str, const PIString & f) {return StdString2PIString(str) + f;}
//! \relatesalso PIChar \brief Output operator to \c std::ostream
inline std::ostream & operator <<(std::ostream & s, const PIChar & v) {
s << v.toCharPtr();
return s;
}
//! \relatesalso PIString @brief Output operator to std::ostream (cout)
inline std::ostream & operator <<(std::ostream & s, const PIString & v) {for (int i = 0; i < v.length(); ++i) s << v[i]; return s;}
//! \relatesalso PIString @brief Input operator from std::istream (cin)
inline std::istream & operator >>(std::istream & s, PIString & v) {std::string ss; s >> ss; v = StdString2PIString(ss); return s;}
//! \relatesalso PIString \brief Return concatenated string
inline PIString operator +(const PIString & f, const std::string & str) {
PIString s(f);
s += StdString2PIString(str);
return s;
}
//! \relatesalso PIStringList @brief Output operator to std::ostream (cout)
//! \relatesalso PIString \brief Return concatenated string
inline PIString operator +(const std::string & str, const PIString & f) {
return StdString2PIString(str) + f;
}
//! \relatesalso PIString \brief Output operator to std::ostream (cout)
inline std::ostream & operator <<(std::ostream & s, const PIString & v) {
for (int i = 0; i < v.length(); ++i) {
s << v[i];
}
return s;
}
//! \relatesalso PIString \brief Input operator from std::istream (cin)
inline std::istream & operator >>(std::istream & s, PIString & v) {
std::string ss;
s >> ss;
v = StdString2PIString(ss);
return s;
}
//! \relatesalso PIStringList \brief Output operator to std::ostream (cout)
inline std::ostream & operator <<(std::ostream & s, const PIStringList & v) {
s << PIChar("{");
for (uint i = 0; i < v.size(); ++i) {

View File

@@ -20,6 +20,66 @@
#include "pistringlist.h"
//! \addtogroup Core
//! \{
//! \~\class PIStringList pistringlist.h
//! \~\brief
//! \~english Based on \a PIDeque<PIString> strings list
//! \~russian Основанный на \a PIDeque<PIString> массив строк
//!
//! \~\details
//!
//! \}
//! \details
//! \~english Example:
//! \~russian Пример:
//! \~\code
//! PIStringList sl("1", "2");
//! sl << "3";
//! piCout << sl.join(" < "); // 1 < 2 < 3
//! \endcode
PIString PIStringList::join(const PIString & delim) const {
PIString s;
for (uint i = 0; i < size(); ++i) {
s += at(i);
if (i < size() - 1)
s += delim;
}
return s;
}
//! \details
//! \~english Example:
//! \~russian Пример:
//! \~\code
//! PIStringList sl("1", "2");
//! sl << "1" << "2" << "3";
//! piCout << sl; // {"1", "2", "1", "2", "3"}
//! piCout << sl.removeStrings("1"); // {"2", "2", "3"}
//! \endcode
PIStringList & PIStringList::removeStrings(const PIString & value) {
for (uint i = 0; i < size(); ++i) {
if (at(i) == value) {
remove(i);
--i;
}
}
return *this;
}
//! \details
//! \~english Example:
//! \~russian Пример:
//! \~\code
//! PIStringList sl("1", "2");
//! sl << "1" << "2" << "3";
//! piCout << sl; // {"1", "2", "1", "2", "3"}
//! piCout << sl.removeDuplicates(); // {"1", "2", "3"}
//! \endcode
PIStringList& PIStringList::removeDuplicates() {
PIStringList l;
PIString s;
@@ -40,3 +100,18 @@ PIStringList& PIStringList::removeDuplicates() {
}
return *this;
}
//! \details
//! \~english Example:
//! \~russian Пример:
//! \~\code
//! PIStringList sl(" 1 ", "\t2", " 3\n");
//! piCout << sl; // {" 1 ", " 2", " 3\n"}
//! piCout << sl.trim(); // {"1", "2", "3"}
//! \endcode
PIStringList & PIStringList::trim() {
for (uint i = 0; i < size(); ++i)
(*this)[i].trim();
return *this;
}

View File

@@ -1,6 +1,9 @@
/*! @brief Strings array class
* \details This class is based on \a PIDeque<PIString> and
* expand it functionality. */
/*! \file pistringlist.h
* \ingroup Core
* \~\brief
* \~english Based on \a PIDeque<PIString> strings list
* \~russian Основанный на \a PIDeque<PIString> массив строк
*/
/*
PIP - Platform Independent Primitives
Strings array class
@@ -30,80 +33,108 @@ class PIP_EXPORT PIStringList: public PIDeque<PIString>
{
public:
//! Contructs empty strings list
//! \~english Contructs an empty strings list
//! \~russian Создает пустой список строк
PIStringList() {;}
~PIStringList() {;}
//! Contructs strings list with one string "str"
//! \~english Contructs strings list with one string "str"
//! \~russian Создает список строк с одной строкой "str"
PIStringList(const PIString & str) {push_back(str);}
PIStringList(PIString && str) {push_back(std::move(str));}
//! Contructs empty strings list with strings "s0" and "s1"
//! \~english Contructs strings list with strings "s0" and "s1"
//! \~russian Создает список строк со строками "s0" и "s1"
PIStringList(const PIString & s0, const PIString & s1) {push_back(s0); push_back(s1);}
PIStringList(PIString && s0, PIString && s1) {push_back(std::move(s0)); push_back(std::move(s1));}
//! Contructs empty strings list with strings "s0", "s1" and "s2"
//! \~english Contructs strings list with strings "s0", "s1" and "s2"
//! \~russian Создает список строк со строками "s0", "s1" и "s2"
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2) {push_back(s0); push_back(s1); push_back(s2);}
PIStringList(PIString && s0, PIString && s1, PIString && s2) {push_back(std::move(s0)); push_back(std::move(s1)); push_back(std::move(s2));}
//! Contructs empty strings list with strings "s0", "s1", "s2" and "s3"
//! \~english Contructs strings list with strings "s0", "s1", "s2" and "s3"
//! \~russian Создает список строк со строками "s0", "s1", "s2" и "s3"
PIStringList(const PIString & s0, const PIString & s1, const PIString & s2, const PIString & s3) {push_back(s0); push_back(s1); push_back(s2); push_back(s3);}
PIStringList(PIString && s0, PIString && s1, PIString && s2, PIString && s3) {push_back(std::move(s0)); push_back(std::move(s1)); push_back(std::move(s2)); push_back(std::move(s3));}
//! \~english Contructs strings list with strings "o"
//! \~russian Создает список строк со строками "o"
PIStringList(const PIStringList & o): PIDeque<PIString>(o) {}
PIStringList(PIStringList && o): PIDeque<PIString>(std::move(o)) {}
//! \~english Contructs strings list with strings "o"
//! \~russian Создает список строк со строками "o"
PIStringList(const PIVector<PIString> & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
//! \~english Contructs strings list with strings "o"
//! \~russian Создает список строк со строками "o"
PIStringList(const PIDeque<PIString> & o): PIDeque<PIString>() {resize(o.size()); for (uint i = 0; i < size(); ++i) (*this)[i] = o[i];}
//! Contructs strings list with std::initializer_list
//! \~english Contructs strings list with strings "init_list" in std::initializer_list format
//! \~russian Создает список строк со строками "init_list" в формате std::initializer_list
PIStringList(std::initializer_list<PIString> init_list): PIDeque<PIString>(init_list) {}
//! @brief Join all strings in one with delimiter "delim" and return it
//! \details Example: \snippet pistring.cpp PIStringList::join
PIString join(const PIString & delim) const {PIString s; for (uint i = 0; i < size(); ++i) {s += at(i); if (i < size() - 1) s += delim;} return s;}
//! \~english Join all strings in one with delimiter "delim" and returns it
//! \~russian Соединяет все строки в одну через разделитель "delim" и возвращает её
PIString join(const PIString & delim) const;
//! @brief Remove all strings equal "value" and return this
//! \details Example: \snippet pistring.cpp PIStringList::removeStrings
PIStringList & removeStrings(const PIString & value) {for (uint i = 0; i < size(); ++i) {if (at(i) == value) {remove(i); --i;}} return *this;}
//! \~english Remove all strings equal "value" and returns reference to this
//! \~russian Удаляет все строки равные "value" и возвращает ссылку на этот список строк
PIStringList & removeStrings(const PIString & value);
PIStringList & remove(uint num) {PIDeque<PIString>::remove(num); return *this;}
PIStringList & remove(uint num, uint count) {PIDeque<PIString>::remove(num, count); return *this;}
//! @brief Remove duplicated strings and return this
//! \details Example: \snippet pistring.cpp PIStringList::removeDuplicates
//! \~english Remove duplicated strings and returns reference to this
//! \~russian Удаляет все дублированные строки и возвращает ссылку на этот список строк
PIStringList & removeDuplicates();
//! @brief Trim all strings
//! \details Example: \snippet pistring.cpp PIString::trim
PIStringList & trim() {for (uint i = 0; i < size(); ++i) (*this)[i].trim(); return *this;}
//! \~english Trim all strings and returns reference to this
//! \~russian Подчищает у всех строк пробельные символы в начале и в конце и возвращает ссылку на этот список строк
PIStringList & trim();
//! Return sum of lengths of all strings
//! \~english Returns sum of lengths of all strings
//! \~russian Возвращает сумму длин всех строк
uint contentSize() {uint s = 0; for (uint i = 0; i < size(); ++i) s += at(i).size(); return s;}
//! Compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const PIStringList & o) const {if (size() != o.size()) return false; for (size_t i = 0; i < size(); ++i) if (o[i] != (*this)[i]) return false; return true;}
//! Compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const PIStringList & o) const {return !(o == (*this));}
//! \~english Assign operator
//! \~russian Оператор присваивания
PIStringList & operator =(const PIStringList & o) {PIDeque<PIString>::operator=(o); return *this;}
//! \~english Append string "str"
//! \~russian Добавляет строку "str"
PIStringList & operator <<(const PIString & str) {append(str); return *this;}
PIStringList & operator <<(PIString && str) {append(std::move(str)); return *this;}
//! \~english Append strings list "sl"
//! \~russian Добавляет список строк "sl"
PIStringList & operator <<(const PIStringList & sl) {append(sl); return *this;}
};
//! \relatesalso PIByteArray @brief Output operator to PIByteArray
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const PIStringList & v) {s << int(v.size_s()); for (int i = 0; i < v.size_s(); ++i) s << v[i]; return s;}
//! relatesalso PIByteArray @brief Input operator from PIByteArray
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, PIStringList & v) {int sz; s >> sz; v.resize(sz); for (int i = 0; i < sz; ++i) s >> v[i]; return s;}
//! \relatesalso PICout @brief Output operator to PICout
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
inline PICout operator <<(PICout s, const PIStringList & v) {s.space(); s.setControl(0, true); s << "{"; for (uint i = 0; i < v.size(); ++i) {s << "\"" << v[i] << "\""; if (i < v.size() - 1) s << ", ";} s << "}"; s.restoreControl(); return s;}
#endif // PISTRINGLIST_H

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