270 Commits
zmq ... pimap

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

1
.gitignore vendored
View File

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

View File

@@ -2,15 +2,52 @@ cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip) project(pip)
set(pip_MAJOR 2) set(pip_MAJOR 2)
set(pip_MINOR 28) set(pip_MINOR 39)
set(pip_REVISION 1) set(pip_REVISION 0)
set(pip_SUFFIX ) set(pip_SUFFIX )
set(pip_COMPANY SHS) set(pip_COMPANY SHS)
set(pip_DOMAIN org.SHS) set(pip_DOMAIN org.SHS)
set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT)
set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cmake-download/CMakeLists.txt"
"# This file was generated by PIP CMake, don`t edit it!
cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE)
include(ExternalProject)
ExternalProject_Add(cmake
GIT_REPOSITORY https://git.shs.tools/SHS/cmake.git
GIT_TAG \"origin/master\"
GIT_CONFIG \"advice.detachedHead=false\"
SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-src\"
BINARY_DIR \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\"
INSTALL_COMMAND \"\"
TEST_COMMAND \"\"
)
")
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
if(result)
message(FATAL_ERROR "CMake step for cmake failed: ${result}")
endif()
execute_process(COMMAND "${CMAKE_COMMAND}" --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cmake-download)
if(result)
message(FATAL_ERROR "Build step for cmake failed: ${result}")
endif()
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_CURRENT_BINARY_DIR}/cmake-build\" --target install)")
set(GIT_CMAKE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake-src")
endif()
if ("x${CMAKE_MODULE_PATH}" STREQUAL "x") if ("x${CMAKE_MODULE_PATH}" STREQUAL "x")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
endif() endif()
if (NOT "x${GIT_CMAKE_DIR}" STREQUAL "x")
list(APPEND CMAKE_MODULE_PATH "${GIT_CMAKE_DIR}")
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
include(CheckFunctionExists) include(CheckFunctionExists)
include(PIPMacros) include(PIPMacros)
@@ -284,7 +321,7 @@ endif()
if(APPLE) if(APPLE)
add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE) add_definitions(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
endif() 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) include_directories(${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include)
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include") #message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include") #message("${ANDROID_NDK}/sysroot/usr/include")
@@ -320,7 +357,7 @@ if(WIN32)
set(CMAKE_CXX_FLAGS "/O2 /Ob2 /Ot /W0") set(CMAKE_CXX_FLAGS "/O2 /Ob2 /Ot /W0")
endif() endif()
else() 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) if(DEFINED ENV{QNX_HOST} OR PIP_FREERTOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32")
endif() endif()
@@ -451,7 +488,7 @@ if (NOT CROSSTOOLS)
#target_link_libraries(pip_plugin pip) #target_link_libraries(pip_plugin pip)
add_executable(pip_test "main.cpp") add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_cloud pip_lua) target_link_libraries(pip_test pip)
endif() endif()
else() else()
@@ -550,25 +587,38 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
include(PIPDocumentation) include(PIPDocumentation)
find_package(Doxygen) find_package(Doxygen)
if(DOXYGEN_FOUND) 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_PROJECT_NUMBER "${pip_VERSION}")
set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${pip_VERSION}\"") set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${pip_VERSION}\"") set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"") set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"")
set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"") set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"") 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) 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_DOT_PATH "\"${_DOT_PATH}\"")
set(DOXY_MSCGEN_PATH "\"${_DOT_PATH}\"")
set(DOXY_DIA_PATH "\"${_DOT_PATH}\"") set(DOXY_DIA_PATH "\"${_DOT_PATH}\"")
endif() endif()
set(DOXY_INPUT) set(DOXY_INPUT)
foreach(F ${PIP_MAIN_FOLDERS}) foreach(F ${PIP_MAIN_FOLDERS})
list(APPEND DOXY_INPUT "\"${F}\"") list(APPEND DOXY_INPUT "\"${F}\"")
endforeach(F) endforeach(F)
string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\"") string(REPLACE ";" " " DOXY_INPUT "\"${CMAKE_CURRENT_SOURCE_DIR}/libs\";\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pages\"")
string(REPLACE ";" " " DOXY_INCLUDE_PATH "${DOXY_INPUT}") string(REPLACE ";" " " DOXY_INCLUDE_PATH "${PIP_INCLUDES}")
string(REPLACE ";" " " DOXY_DEFINES "${PIP_EXPORTS};DOXYGEN;PIOBJECT;PIOBJECT_SUBCLASS") string(REPLACE ";" " " DOXY_DEFINES "${DOXY_DEFINES}")
add_documentation(doc doc/Doxyfile.in) add_documentation(doc doc/Doxyfile.in)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/html DESTINATION ../share/doc/pip COMPONENT doc EXCLUDE_FROM_ALL OPTIONAL)
endif() endif()

View File

@@ -33,4 +33,10 @@ You should add ${<out_var>} to your target.
## Documentation ## 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(PTHREAD_LIBRARY pthread)
find_library(UTIL_LIBRARY util) find_library(UTIL_LIBRARY util)
set(_PIP_ADD_LIBS_ ${PTHREAD_LIBRARY} ${UTIL_LIBRARY}) 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_}) list(APPEND PIP_LIBRARY ${_PIP_ADD_LIBS_})
endif() endif()
endif() endif()

View File

@@ -1,7 +1,7 @@
macro(ADD_DOCUMENTATION TARGET DOXYGEN_CONFIG_FILE) macro(ADD_DOCUMENTATION TARGET DOXYGEN_CONFIG_FILE)
if(DOXYGEN_FOUND) if(DOXYGEN_FOUND)
configure_file("${PROJECT_SOURCE_DIR}/${DOXYGEN_CONFIG_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/doxyfile-${TARGET}") 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_custom_target("${TARGET}" COMMAND ${CMAKE_COMMAND} -D COMPONENT=doc -P cmake_install.cmake)
add_dependencies("${TARGET}" "genereate.${TARGET}") add_dependencies("${TARGET}" "genereate.${TARGET}")
else(DOXYGEN_FOUND) 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 # This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project. # 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 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory. # 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 # 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 # into which the generated documentation will be written. If a relative path is
@@ -91,7 +91,7 @@ ALLOW_UNICODE_NAMES = NO
# Ukrainian and Vietnamese. # Ukrainian and Vietnamese.
# The default value is: English. # 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 # The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this # 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 # shortest path that makes the file name unique will be used
# The default value is: YES. # 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. # 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 # Stripping is only done if one of the specified strings matches the left-hand
@@ -197,10 +197,20 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = 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 # 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 # 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 # 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. # The default value is: NO.
QT_AUTOBRIEF = NO QT_AUTOBRIEF = NO
@@ -215,7 +225,15 @@ QT_AUTOBRIEF = NO
# not recognized any more. # not recognized any more.
# The default value is: NO. # 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 # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements. # documentation from any documented member that it re-implements.
@@ -256,12 +274,6 @@ ALIASES = "handlers=\name Handlers" \
"events=\name Events" \ "events=\name Events" \
"ioparams=\name Configurable parameters" "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 # 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 # 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 # 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 # 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 # 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 # 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, # language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, # Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # 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 # 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 # default for Fortran type files). For instance to make doxygen treat .inc files
# .inc files as Fortran files (default is PHP), and .f files as C (default is # as Fortran files (default is PHP), and .f files as C (default is Fortran),
# Fortran), use: inc=Fortran f=C. # use: inc=Fortran f=C.
# #
# Note: For files without extension you can use no_extension as a placeholder. # 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 # 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 = EXTENSION_MAPPING =
@@ -332,7 +347,7 @@ MARKDOWN_SUPPORT = YES
# to that level are automatically included in the table of contents, even if # to that level are automatically included in the table of contents, even if
# they do not have an id attribute. # they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings. # 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. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 0 TOC_INCLUDE_HEADINGS = 0
@@ -353,7 +368,7 @@ AUTOLINK_SUPPORT = YES
# diagrams that involve STL classes more complete and accurate. # diagrams that involve STL classes more complete and accurate.
# The default value is: NO. # 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 # If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support. # enable parsing support.
@@ -448,6 +463,19 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0 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 # Build related configuration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -468,6 +496,12 @@ EXTRACT_ALL = NO
EXTRACT_PRIVATE = 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 # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation. # scope will be included in the documentation.
# The default value is: NO. # The default value is: NO.
@@ -505,6 +539,13 @@ EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = NO 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 # 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 # undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation # members will be included in the various overviews, but no documentation
@@ -522,8 +563,8 @@ HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_CLASSES = YES
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # 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 # declarations. If set to NO, these declarations will be included in the
# included in the documentation. # documentation.
# The default value is: NO. # The default value is: NO.
HIDE_FRIEND_COMPOUNDS = YES HIDE_FRIEND_COMPOUNDS = YES
@@ -542,11 +583,18 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# names in lower-case letters. If set to YES, upper-case letters are also # able to match the capabilities of the underlying filesystem. In case the
# allowed. This is useful if you have classes or files whose names only differ # filesystem is case sensitive (i.e. it supports files in the same directory
# in case and if your file system supports case sensitive file names. Windows # whose names only differ in casing), the option must be set to YES to properly
# and Mac users are advised to set this option to NO. # 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. # The default value is: system dependent.
CASE_SENSE_NAMES = NO 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 files that are included by a file in the documentation of that file.
# The default value is: YES. # 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 # 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 # grouped member an include statement to the documentation, telling the reader
# which file to include in order to use the member. # which file to include in order to use the member.
# The default value is: NO. # 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 # 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. # 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 WARN_NO_PARAMDOC = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # 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. # The default value is: NO.
WARN_AS_ERROR = 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 # 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 # 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 # 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 # documentation (see:
# possible encodings. # https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8. # The default value is: UTF-8.
INPUT_ENCODING = 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 # need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen. # 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, # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, # *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. # *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
# *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \ FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \ *.cpp \
*.c++ \
*.d \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \ *.h \
*.hh \ *.md
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.f90 \
*.f \
*.for \
*.vhd \
*.vhdl
# The RECURSIVE tag can be used to specify whether or not subdirectories should # The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well. # be searched for input files as well.
@@ -1087,16 +1112,22 @@ USE_HTAGS = NO
VERBATIM_HEADERS = NO VERBATIM_HEADERS = NO
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # 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 # clang parser (see:
# cost of reduced performance. This can be particularly helpful with template # http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# rich C++ code for which doxygen's built-in parser lacks the necessary type # performance. This can be particularly helpful with template rich C++ code for
# information. # which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was # Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake. # generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO. # The default value is: NO.
CLANG_ASSISTED_PARSING = 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 # 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 # 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 # the include paths will already be set by doxygen for the files and directories
@@ -1106,10 +1137,13 @@ CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS = CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the # If clang assisted parsing is enabled you can provide the clang parser with the
# path to the compilation database (see: # path to the directory containing a file called compile_commands.json. This
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files # file is the compilation database (see:
# were built. This is equivalent to specifying the "-p" option to a clang tool, # http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# such as clang-check. These options will then be passed to the parser. # 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 # Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake. # generated with the -Duse_libclang=ON option for CMake.
@@ -1126,13 +1160,6 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES 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 # 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 # 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 # 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. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).
@@ -1239,7 +1266,7 @@ HTML_EXTRA_FILES =
# Minimum value: 0, maximum value: 359, default value: 220. # Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # 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 # 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. # Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100 # 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 # 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 # 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 # 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. # like the Qt help browser.
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to 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. # Minimum value: 0, maximum value: 9999, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # 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 # generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: https://developer.apple.com/xcode/), introduced with OSX # environment (see:
# 10.5 (Leopard). To create a documentation set, doxygen will generate a # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# Makefile in the HTML output directory. Running make will produce the docset in # create a documentation set, doxygen will generate a Makefile in the HTML
# that directory and running make install will install the docset in # 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 # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information. # genXcode/_index.html for more information.
@@ -1329,7 +1357,7 @@ DOCSET_FEEDNAME = "Doxygen generated docs"
# The default value is: org.doxygen.Project. # The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_DOCSET is set to YES. # 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 DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style # 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. # The default value is: org.doxygen.Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES. # 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 DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
# The default value is: Publisher. # The default value is: Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES. # 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 # 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 # 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 # 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 # (see:
# Windows. # 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 # 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 # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@@ -1379,7 +1407,7 @@ CHM_FILE =
HHC_LOCATION = HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated # 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. # The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES. # This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1420,11 +1448,12 @@ GENERATE_QHP = YES
# the HTML output folder. # the HTML output folder.
# This tag requires that the tag GENERATE_QHP is set to YES. # 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 # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace # 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. # The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES. # 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 # 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 # 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 (see:
# folders). # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc. # The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES. # 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 # 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 # 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 (see:
# filters). # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME = PIP QHP_CUST_FILTER_NAME = PIP
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # 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 # 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 (see:
# filters). # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS = ${DOXY_QHP_CUST_FILTER_ATTRS} QHP_CUST_FILTER_ATTRS = ${DOXY_QHP_CUST_FILTER_ATTRS}
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see: # 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. # This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS = ${DOXY_QHP_SECT_FILTER_ATTRS} QHP_SECT_FILTER_ATTRS = ${DOXY_QHP_SECT_FILTER_ATTRS}
# The QHG_LOCATION tag can be used to specify the location of Qt's # The QHG_LOCATION tag can be used to specify the location (absolute path
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# generated .qhp file. # run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES. # This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION = qhelpgenerator QHG_LOCATION = qhelpgenerator
@@ -1487,7 +1516,7 @@ GENERATE_ECLIPSEHELP = NO
# The default value is: org.doxygen.Project. # The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. # 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 # 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 # 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. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # 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 # 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. # doxygen will group on one line in the generated HTML documentation.
@@ -1541,6 +1570,17 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO 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 # 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 # 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 # doxygen run you need to manually remove any form_*.png images from the HTML
@@ -1561,8 +1601,14 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES 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 # 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 # 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 # 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 # 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 # When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see: # 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 # Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG. # compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS. # 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 # 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. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment. # 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. # This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 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 # 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 # 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. # example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES. # This tag requires that the tag USE_MATHJAX is set to YES.
@@ -1629,10 +1676,10 @@ MATHJAX_CODEFILE =
# The default value is: YES. # The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to 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 # 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 # 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 # 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 # 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 # Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library # (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. # See the section "External Indexing and Searching" for details.
# The default value is: NO. # The default value is: NO.
@@ -1664,8 +1712,9 @@ EXTERNAL_SEARCH = NO
# #
# Doxygen ships with an example indexer (doxyindexer) and search engine # Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library # (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/). See the section "External Indexing and # Xapian (see:
# Searching" for details. # https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES. # This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL = SEARCHENGINE_URL =
@@ -1736,13 +1785,14 @@ LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to # 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). # Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. # 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. # 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 # 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 # documents. This may be useful for small projects and may help to save some
@@ -1828,9 +1878,11 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate # If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# the PDF file directly from the LaTeX files. Set this option to YES, to get a # specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# higher quality PDF documentation. # 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. # The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to 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. # recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # 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 # 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 # 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. # 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 # 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 # the class index. If set to NO, only the inherited external classes will be
@@ -2232,12 +2284,6 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = 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 # Configuration options related to the dot tool
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@@ -2251,15 +2297,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES 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 # 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 # 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. # 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 # but if the number exceeds 15, the total amount of fields shown is limited to
# 10. # 10.
# Minimum value: 0, maximum value: 100, default value: 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 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 # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their # collaboration graphs will show the relations between templates and their
# instances. # instances.
@@ -2550,9 +2609,11 @@ DOT_MULTI_TARGETS = YES
GENERATE_LEGEND = 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. # 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. # The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES DOT_CLEANUP = YES

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ void _() {
//! [0] //! [0]
class SomeIO: public PIIODevice { class SomeIO: public PIIODevice {
PIIODEVICE(SomeIO) PIIODEVICE(SomeIO, "myio")
public: public:
SomeIO(): PIIODevice() {} SomeIO(): PIIODevice() {}
protected: protected:
@@ -19,9 +19,8 @@ protected:
// write to your device here // write to your device here
return written_bytes; return written_bytes;
} }
PIString fullPathPrefix() const {return "myio";}
void configureFromFullPath(const PIString & full_path) { void configureFromFullPath(const PIString & full_path) {
// parse full_path and configure device there // parse full_path and configure device here
} }
}; };
REGISTER_DEVICE(SomeIO) REGISTER_DEVICE(SomeIO)

View File

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

View File

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

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

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

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

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

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

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

BIN
doc/pip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

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

View File

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

View File

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

View File

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

View File

@@ -23,6 +23,7 @@
# include <fcntl.h> # include <fcntl.h>
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE # ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
@@ -62,7 +63,7 @@ PIScreen::SystemConsole::SystemConsole() {
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode); GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo); GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
#else #else
# ifdef FREERTOS # ifdef MICRO_PIP
w = 80; w = 80;
h = 24; h = 24;
# else # else
@@ -108,16 +109,13 @@ void PIScreen::SystemConsole::end() {
void PIScreen::SystemConsole::prepare() { void PIScreen::SystemConsole::prepare() {
int w, h; int w = 80, h = 24;
#ifdef WINDOWS #ifdef WINDOWS
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi); GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1; w = PRIVATE->csbi.srWindow.Right - PRIVATE->csbi.srWindow.Left + 1;
h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1; h = PRIVATE->csbi.srWindow.Bottom - PRIVATE->csbi.srWindow.Top + 1;
#else #else
# ifdef FREERTOS # ifndef MICRO_PIP
w = 80;
h = 24;
# else
winsize ws; winsize ws;
ioctl(0, TIOCGWINSZ, &ws); ioctl(0, TIOCGWINSZ, &ws);
w = ws.ws_col; w = ws.ws_col;
@@ -144,7 +142,7 @@ void PIScreen::SystemConsole::resize(int w, int h) {
pcells.resize(height); pcells.resize(height);
for (int i = 0; i < height; ++i) { for (int i = 0; i < height; ++i) {
cells[i].resize(width); cells[i].resize(width);
pcells[i].resize(width, Cell(0)); pcells[i].resize(width, Cell(PIChar()));
} }
#ifdef WINDOWS #ifdef WINDOWS
PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow; PRIVATE->sbi.srWindow = PRIVATE->csbi.srWindow;
@@ -221,14 +219,15 @@ void PIScreen::SystemConsole::print() {
} else { } else {
if (!s.isEmpty()) { if (!s.isEmpty()) {
moveTo(si, sj); moveTo(si, sj);
printf("%s", s.data()); PICout::stdoutPIString(s);
s.clear(); s.clear();
} }
} }
} }
if (!s.isEmpty()) { if (!s.isEmpty()) {
moveTo(si, sj); moveTo(si, sj);
printf("%s", s.data()); PICout::stdoutPIString(s);
//printf("%s", s.data());
s.clear(); s.clear();
} }
} }
@@ -297,32 +296,32 @@ void PIScreen::SystemConsole::newLine() {
} }
#else // WINDOWS #else // WINDOWS
PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) { PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) {
PIString ts("\e[0"); PIString ts = PIStringAscii("\e[0");
switch (c.format.color_char) { switch (c.format.color_char) {
case Black: ts += ";30"; break; case Black: ts += PIStringAscii(";30"); break;
case Red: ts += ";31"; break; case Red: ts += PIStringAscii(";31"); break;
case Green: ts += ";32"; break; case Green: ts += PIStringAscii(";32"); break;
case Blue: ts += ";34"; break; case Blue: ts += PIStringAscii(";34"); break;
case Cyan: ts += ";36"; break; case Cyan: ts += PIStringAscii(";36"); break;
case Magenta: ts += ";35"; break; case Magenta: ts += PIStringAscii(";35"); break;
case Yellow: ts += ";33"; break; case Yellow: ts += PIStringAscii(";33"); break;
case White: ts += ";37"; break; case White: ts += PIStringAscii(";37"); break;
} }
switch (c.format.color_back) { switch (c.format.color_back) {
case Black: ts += ";40"; break; case Black: ts += PIStringAscii(";40"); break;
case Red: ts += ";41"; break; case Red: ts += PIStringAscii(";41"); break;
case Green: ts += ";42"; break; case Green: ts += PIStringAscii(";42"); break;
case Blue: ts += ";44"; break; case Blue: ts += PIStringAscii(";44"); break;
case Cyan: ts += ";46"; break; case Cyan: ts += PIStringAscii(";46"); break;
case Magenta: ts += ";45"; break; case Magenta: ts += PIStringAscii(";45"); break;
case Yellow: ts += ";43"; break; case Yellow: ts += PIStringAscii(";43"); break;
case White: ts += ";47"; break; case White: ts += PIStringAscii(";47"); break;
} }
if ((c.format.flags & Bold) == Bold) ts += ";1"; if ((c.format.flags & Bold ) == Bold ) ts += PIStringAscii(";1");
if ((c.format.flags & Underline) == Underline) ts += ";4"; if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4");
if ((c.format.flags & Blink) == Blink) ts += ";5"; if ((c.format.flags & Blink ) == Blink ) ts += PIStringAscii(";5");
if ((c.format.flags & Inverse) == Inverse) ts += ";7"; if ((c.format.flags & Inverse ) == Inverse ) ts += PIStringAscii(";7");
return ts + "m"; return ts + 'm';
} }
#endif // WINDOWS #endif // WINDOWS

View File

@@ -689,13 +689,7 @@ bool TileInput::keyEvent(PIKbdListener::KeyEvent key) {
case PIKbdListener::F12: case PIKbdListener::F12:
break; break;
default: default:
PIChar tc text.insert(cur, PIChar((ushort)key.key));
#ifdef WINDOWS
= PIChar(key.key);
#else
= PIChar::fromUTF8((char *)&(key.key));
#endif
text.insert(cur, tc);
cur++; cur++;
oo++; oo++;
if (cur - offset >= lwid - osp) offset += oo; if (cur - offset >= lwid - osp) offset += oo;

View File

@@ -19,9 +19,10 @@
#include "piincludes_p.h" #include "piincludes_p.h"
#include "piterminal.h" #include "piterminal.h"
#include "pisharedmemory.h" #include "pisharedmemory.h"
#ifndef FREERTOS #ifndef MICRO_PIP
#ifdef WINDOWS #ifdef WINDOWS
# include <windows.h> # include <windows.h>
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# include <winuser.h> # include <winuser.h>
#else #else
@@ -238,9 +239,9 @@ void PITerminal::write(PIKbdListener::KeyEvent ke) {
else { else {
PIByteArray ba; PIByteArray ba;
#ifdef WINDOWS #ifdef WINDOWS
ba << uchar(PIChar(ke.key).toConsole1Byte()); ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
#else #else
ba = PIString(PIChar(ke.key)).toUTF8(); ba = PIString(PIChar((ushort)ke.key)).toUTF8();
#endif #endif
write(ba); write(ba);
} }
@@ -811,11 +812,12 @@ bool PITerminal::initialize() {
//piCoutObj << fr << PRIVATE->fd << pty; //piCoutObj << fr << PRIVATE->fd << pty;
if (fr == 0) { if (fr == 0) {
char ** argv = new char*[2]; char ** argv = new char*[2];
argv[0] = new char[PRIVATE->shell.lengthAscii() + 1]; PIByteArray shell = PRIVATE->shell.toByteArray();
memcpy(argv[0], PRIVATE->shell.dataAscii(), PRIVATE->shell.lengthAscii()); argv[0] = new char[shell.size() + 1];
argv[0][PRIVATE->shell.lengthAscii()] = 0; memcpy(argv[0], shell.data(), shell.size());
argv[0][shell.size()] = 0;
argv[1] = 0; argv[1] = 0;
execvp(PRIVATE->shell.dataAscii(), argv); execvp(argv[0], argv);
delete[] argv[0]; delete[] argv[0];
delete[] argv; delete[] argv;
exit(0); exit(0);
@@ -917,4 +919,4 @@ bool PITerminal::resize(int cols, int rows) {
return ret; return ret;
} }
#endif // FREERTOS #endif // MICRO_PIP

View File

@@ -128,7 +128,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
passwordRequest(&ps); passwordRequest(&ps);
if (ps.isEmpty()) return disconnect(ba, "Canceled by user"); if (ps.isEmpty()) return disconnect(ba, "Canceled by user");
ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray()); ph = crypt.passwordHash(ps, PIString("PIAuth").toByteArray());
ps.fill(PIChar(0)); ps.fill(PIChar());
tba.clear(); tba.clear();
tba << ph << auth_sign << sign_pk; tba << ph << auth_sign << sign_pk;
tba = crypt.crypt(tba, box_pk, box_sk); 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() { size_t PICrypt::sizeHash() {
#ifdef PIP_CRYPT #ifdef PIP_CRYPT
return crypto_generichash_BYTES; return crypto_generichash_BYTES;

View File

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

View File

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

View File

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

View File

@@ -28,7 +28,7 @@
#endif #endif
/** \class PIStreamPacker /** \class PIStreamPacker
* @brief Simple packet wrap aroud any PIIODevice * \brief Simple packet wrap aroud any PIIODevice
* *
* \section PIStreamPacker_synopsis Synopsis * \section PIStreamPacker_synopsis Synopsis
* %PIStreamPacker provides simple pack/unpack logic for any data packets. * %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) { void PIStreamPacker::send(const PIByteArray & data) {
if (data.isEmpty()) return; if (data.isEmpty()) return;
PIByteArray cd; PIByteArray cd;
@@ -94,31 +101,12 @@ void PIStreamPacker::send(const PIByteArray & data) {
hdr << int(cd.size_s()); hdr << int(cd.size_s());
cd.insert(0, hdr); cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0; int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
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) { for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst); if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else part = PIByteArray(cd.data(pst), max_packet_size); else part = PIByteArray(cd.data(pst), max_packet_size);
//piCout << "send" << part.size(); //piCout << "send" << part.size();
sendRequest(part); sendRequest(part);
pst += max_packet_size; pst += max_packet_size;
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; packet_size = sz;
if (packet_size == 0) if (packet_size == 0)
packet_size = -1; 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; continue;
} else { } else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s()); int ps = piMini(stream.size_s(), packet_size - packet.size_s());
packet.append(stream.data(), ps); packet.append(stream.data(), ps);
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); stream.remove(0, ps);
if (packet.size_s() == packet_size) { if (packet.size_s() == packet_size) {
PIByteArray cd; PIByteArray cd;
@@ -211,9 +187,6 @@ void PIStreamPacker::received(const PIByteArray & data) {
} }
packet.clear(); packet.clear();
packet_size = -1; 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(dev, threadedReadEvent, this, received);
CONNECTU(this, sendRequest, dev, write); 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 /*! \file picloudbase.h
* @brief PICloud Base - Base class for PICloudClient and PICloud Server * \ingroup Cloud
*/ * \~\brief
* \~english Base class for PICloudClient and PICloudServer
* \~russian Базовый класс для PICloudClient и PICloudServer
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud Base - Base class for PICloudClient and PICloud Server PICloud Base - Base class for PICloudClient and PICloud Server

View File

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

View File

@@ -16,6 +16,37 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \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 #ifndef PICLOUDMODULE_H
#define PICLOUDMODULE_H #define PICLOUDMODULE_H

View File

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

View File

@@ -1,6 +1,9 @@
/*! @file picloudtcp.h /*! \file picloudtcp.h
* @brief PICloud TCP transport * \ingroup Cloud
*/ * \~\brief
* \~english PICloud TCP transport
* \~russian TCP слой PICloud
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
PICloud TCP transport PICloud TCP transport
@@ -25,6 +28,7 @@
#include "pip_cloud_export.h" #include "pip_cloud_export.h"
#include "pistring.h" #include "pistring.h"
#include "pimutex.h"
class PIEthernet; class PIEthernet;
@@ -52,6 +56,7 @@ public:
Connect = 1, Connect = 1,
Disconnect = 2, Disconnect = 2,
Data = 3, Data = 3,
Ping = 4,
}; };
TCP(PIStreamPacker * s); TCP(PIStreamPacker * s);
@@ -65,8 +70,9 @@ public:
void sendDisconnected(uint client_id); void sendDisconnected(uint client_id);
int sendData(const PIByteArray & data); int sendData(const PIByteArray & data);
int sendData(const PIByteArray & data, uint client_id); int sendData(const PIByteArray & data, uint client_id);
void sendPing();
PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba); PIPair<PICloud::TCP::Type, PICloud::TCP::Role> parseHeader(PIByteArray & ba);
PIByteArray parseData(PIByteArray & ba); bool canParseData(PIByteArray & ba);
PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba); PIPair<uint, PIByteArray> parseDataServer(PIByteArray & ba);
PIByteArray parseConnect_d(PIByteArray & ba); PIByteArray parseConnect_d(PIByteArray & ba);
uint parseConnect(PIByteArray & ba); uint parseConnect(PIByteArray & ba);
@@ -84,6 +90,8 @@ private:
PIByteArray suuid; PIByteArray suuid;
PIString server_name; PIString server_name;
PIStreamPacker * streampacker; PIStreamPacker * streampacker;
PIMutex mutex_send;
}; };
} }

View File

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

View File

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

View File

@@ -16,6 +16,37 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \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 #ifndef PICODEMODULE_H
#define 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]); const PIString & an(args[i]), av(arg_vals[i]);
int ind(-1); int ind(-1);
while ((ind = ret.find(an, ind + 1)) >= 0) { 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 > 1) ppc = ret[ind - 2];
if (ind > 0) pc = ret[ind - 1]; if (ind > 0) pc = ret[ind - 1];
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(),1)[0]; if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(),1)[0];
@@ -190,10 +190,39 @@ void PICodeParser::clear() {
piForeachC (PIString & d, defs) piForeachC (PIString & d, defs)
defines << Define(d, ""); defines << Define(d, "");
defines << Define(PIStringAscii("PICODE"), "") << custom_defines; defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
<< 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) { bool PICodeParser::parseFileContent(PIString & fc, bool main) {
static const PIString s_ns = PIStringAscii("::");
static const PIString s_bo = PIStringAscii("{\n"); static const PIString s_bo = PIStringAscii("{\n");
static const PIString s_bc = PIStringAscii("\n}\n"); static const PIString s_bc = PIStringAscii("\n}\n");
static const PIString s_class = PIStringAscii("class"); static const PIString s_class = PIStringAscii("class");
@@ -250,7 +279,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
piForeachC (Define & d, defines) { piForeachC (Define & d, defines) {
int ind(-1); int ind(-1);
while ((ind = pfc.find(d.first, ind + 1)) >= 0) { while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
PIChar pc(0), nc(0); PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1]; if (ind > 0) pc = pfc[ind - 1];
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(),1)[0]; if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(),1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue; if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
@@ -262,7 +291,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
piForeachC (Macro & m, macros) { piForeachC (Macro & m, macros) {
int ind(-1); int ind(-1);
while ((ind = pfc.find(m.name, ind + 1)) >= 0) { while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
PIChar pc(0), nc(0); PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1]; if (ind > 0) pc = pfc[ind - 1];
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0]; if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue; if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
@@ -280,7 +309,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
replaceMeta(pfc); replaceMeta(pfc);
//piCout << NewLine << "file" << cur_file << pfc; //piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
int pl = -1; int pl = -1;
while (!pfc.isEmpty()) { while (!pfc.isEmpty()) {
pfc.trim(); pfc.trim();
@@ -288,7 +317,12 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (pl == nl) break; if (pl == nl) break;
pl = nl; pl = nl;
if (pfc.left(9) == s_namespace) { 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, true);
cur_namespace = prev_namespace;
continue; continue;
} }
if (pfc.left(8) == s_template) { if (pfc.left(8) == s_template) {
@@ -306,7 +340,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;} if (dind < 0 || find < dind) {pfc.cutLeft(6); continue;}
ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc; ccmn = pfc.left(dind) + s_bo + pfc.mid(dind).takeRange('{', '}') + s_bc;
pfc.remove(0, ccmn.size()); pfc.remove(0, ccmn.size());
parseClass(0, ccmn); parseClass(0, ccmn, false);
continue; continue;
} }
if (pfc.left(4) == s_enum) { if (pfc.left(4) == s_enum) {
@@ -391,7 +425,7 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
} }
PIString PICodeParser::parseClass(Entity * parent, PIString & fc) { void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace) {
static const PIString s_ns = PIStringAscii("::"); static const PIString s_ns = PIStringAscii("::");
static const PIString s_public = PIStringAscii("public"); static const PIString s_public = PIStringAscii("public");
static const PIString s_protected = PIStringAscii("protected"); static const PIString s_protected = PIStringAscii("protected");
@@ -402,22 +436,31 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
static const PIString s_enum = PIStringAscii("enum"); static const PIString s_enum = PIStringAscii("enum");
static const PIString s_friend = PIStringAscii("friend"); static const PIString s_friend = PIStringAscii("friend");
static const PIString s_typedef = PIStringAscii("typedef"); static const PIString s_typedef = PIStringAscii("typedef");
static const PIString s_namespace = PIStringAscii("namespace");
static const PIString s_template = PIStringAscii("template"); static const PIString s_template = PIStringAscii("template");
Visibility prev_vis = cur_def_vis; Visibility prev_vis = cur_def_vis;
int dind = fc.find('{'), find = fc.find(';'), end = 0; int dind = fc.find('{'), find = fc.find(';'), end = 0;
if (dind < 0 && find < 0) return PIString(); if (dind < 0 && find < 0) return;
if (dind < 0 || find < dind) return fc.left(find); if (dind < 0 || find < dind) {
//piCout << "parse class <****\n" << fc.left(20) << "\n****>"; fc.left(find);
Entity * ce = parseClassDeclaration(fc.takeLeft(dind)); return;
fc.trim().cutLeft(1).cutRight(1).trim(); }
//piCout << "parse class <****\n" << fc << "\n****>";
Entity * ce = parent;
if (!is_namespace) {
ce = parseClassDeclaration(fc.takeLeft(dind));
fc.trim().cutLeft(1).cutRight(1).trim();
}
//piCout << "found class <****\n" << fc << "\n****>"; //piCout << "found class <****\n" << fc << "\n****>";
if (!ce) return PIString(); ///if (!ce) return PIString();
if (parent) parent->children << ce; if (ce) {
ce->parent_scope = parent; if (parent) parent->children << ce;
ce->parent_scope = parent;
}
int ps = -1; int ps = -1;
bool def = false; bool def = false;
PIString prev_namespace = cur_namespace, stmp; PIString prev_namespace = cur_namespace, stmp;
cur_namespace = ce->name + s_ns; if (ce) cur_namespace += ce->name + s_ns;
//piCout << "parse class" << ce->name << "namespace" << cur_namespace; //piCout << "parse class" << ce->name << "namespace" << cur_namespace;
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace; //piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) { while (!fc.isEmpty()) {
@@ -426,6 +469,14 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
if (cw == s_public ) {cur_def_vis = Public; fc.cutLeft(1); continue;} if (cw == s_public ) {cur_def_vis = Public; fc.cutLeft(1); continue;}
if (cw == s_protected) {cur_def_vis = Protected; fc.cutLeft(1); continue;} if (cw == s_protected) {cur_def_vis = Protected; fc.cutLeft(1); continue;}
if (cw == s_private ) {cur_def_vis = Private; fc.cutLeft(1); continue;} if (cw == s_private ) {cur_def_vis = Private; fc.cutLeft(1); continue;}
if (cw == s_namespace) {
PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += fc.takeCWord() + s_ns;
ccmn = fc.takeRange('{', '}');
parseClass(ce, ccmn, true);
cur_namespace = prev_namespace;
continue;
}
if (cw == s_class || cw == s_struct || cw == s_union) { if (cw == s_class || cw == s_struct || cw == s_union) {
if (isDeclaration(fc, 0, &end)) { if (isDeclaration(fc, 0, &end)) {
fc.cutLeft(end); fc.cutLeft(end);
@@ -436,7 +487,7 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
stmp = fc.takeRange('{', '}'); stmp = fc.takeRange('{', '}');
fc.takeSymbol(); fc.takeSymbol();
stmp = cw + ' ' + tmp + '{' + stmp + '}'; stmp = cw + ' ' + tmp + '{' + stmp + '}';
parseClass(ce, stmp); parseClass(ce, stmp, false);
continue; continue;
} }
if (cw == s_enum) { if (cw == s_enum) {
@@ -449,11 +500,13 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
} }
if (cw == s_friend) {fc.cutLeft(fc.find(';') + 1); continue;} if (cw == s_friend) {fc.cutLeft(fc.find(';') + 1); continue;}
if (cw == s_typedef) { if (cw == s_typedef) {
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';'))); if (ce) {
typedefs << ce->typedefs.back(); ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
typedefs.back().first.insert(0, cur_namespace); typedefs << ce->typedefs.back();
if (ce->typedefs.back().first.isEmpty()) typedefs.back().first.insert(0, cur_namespace);
ce->typedefs.pop_back(); if (ce->typedefs.back().first.isEmpty())
ce->typedefs.pop_back();
}
fc.takeSymbol(); fc.takeSymbol();
continue; continue;
} }
@@ -467,7 +520,7 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
} }
def = !isDeclaration(fc, 0, &end); def = !isDeclaration(fc, 0, &end);
tmp = (cw + fc.takeLeft(end)).trim(); tmp = (cw + fc.takeLeft(end)).trim();
if (!tmp.isEmpty()) if (!tmp.isEmpty() && ce)
parseMember(ce, tmp); parseMember(ce, tmp);
if (def) fc.takeRange('{', '}'); if (def) fc.takeRange('{', '}');
else fc.takeSymbol(); else fc.takeSymbol();
@@ -476,7 +529,6 @@ PIString PICodeParser::parseClass(Entity * parent, PIString & fc) {
} }
cur_def_vis = prev_vis; cur_def_vis = prev_vis;
cur_namespace = prev_namespace; cur_namespace = prev_namespace;
return ce->name;
} }
@@ -1052,10 +1104,10 @@ PIString PICodeParser::procMacros(PIString fc) {
bool PICodeParser::parseDirective(PIString d) { bool PICodeParser::parseDirective(PIString d) {
static const PIString s_include = PIStringAscii("include"); static const PIString s_include = PIStringAscii("include");
static const PIString s_define = PIStringAscii("define"); static const PIString s_define = PIStringAscii("define");
static const PIString s_undef = PIStringAscii("undef"); static const PIString s_undef = PIStringAscii("undef");
static const PIString s_PIMETA = PIStringAscii("PIMETA"); static const PIString s_PIMETA = PIStringAscii("PIMETA");
if (d.isEmpty()) return true; if (d.isEmpty()) return true;
PIString dname = d.takeCWord(); PIString dname = d.takeCWord();
//piCout << "parseDirective" << d; //piCout << "parseDirective" << d;
@@ -1074,9 +1126,19 @@ bool PICodeParser::parseDirective(PIString d) {
if (mname == s_PIMETA) return true; if (mname == s_PIMETA) return true;
if (d.left(1) == PIChar('(')) { // macro if (d.left(1) == PIChar('(')) { // macro
PIStringList args = d.takeRange('(', ')').split(',').trim(); 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); macros << Macro(mname, d.trim(), args);
} else { // define } else { // define
d.trim(); d.trim();
for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) {
defines.remove(i);
break;
}
defines << Define(mname, d); defines << Define(mname, d);
evaluator.setVariable(mname, complexd_1); evaluator.setVariable(mname, complexd_1);
} }

View File

@@ -1,6 +1,9 @@
/*! @file picodeparser.h /*! \file picodeparser.h
* @brief C++ code parser * \ingroup Code
*/ * \~\brief
* \~english C++ code parser
* \~russian Разбор C++ кода
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
C++ code parser C++ code parser
@@ -148,7 +151,7 @@ private:
bool parseFileContent(PIString & fc, bool main); bool parseFileContent(PIString & fc, bool main);
bool parseDirective(PIString d); bool parseDirective(PIString d);
Entity * parseClassDeclaration(const PIString & fc); Entity * parseClassDeclaration(const PIString & fc);
PIString parseClass(Entity * parent, PIString & fc); void parseClass(Entity * parent, PIString & fc, bool is_namespace);
MetaMap parseMeta(PIString & fc); MetaMap parseMeta(PIString & fc);
bool parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta); bool parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta);
Typedef parseTypedef(PIString fc); Typedef parseTypedef(PIString fc);

View File

@@ -1,6 +1,10 @@
/*! @file picompress.h /*! \file picompress.h
* @brief Compress class using zlib * \brief
*/ * \ingroup Compress
* \~\brief
* \~english Compress class zlib
* \~russian Сжатие с помощью zlib
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Compress class using zlib Compress class using zlib
@@ -19,6 +23,37 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \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 #ifndef PICOMPRESS_H
#define PICOMPRESS_H #define PICOMPRESS_H
@@ -26,8 +61,16 @@
#include "pip_compress_export.h" #include "pip_compress_export.h"
#include "pibytearray.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); 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); PIP_COMPRESS_EXPORT PIByteArray piDecompress(const PIByteArray & zba);
#endif // PICOMPRESS_H #endif // PICOMPRESS_H

View File

@@ -16,6 +16,37 @@
You should have received a copy of the GNU Lesser General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \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 #ifndef PICONSOLEMODULE_H
#define PICONSOLEMODULE_H #define PICONSOLEMODULE_H

View File

@@ -21,11 +21,12 @@
#ifndef WINDOWS #ifndef WINDOWS
# include <termios.h> # include <termios.h>
#else #else
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
#endif #endif
/** \class PIKbdListener /** \class PIKbdListener
* @brief Keyboard console input listener * \brief Keyboard console input listener
* \details This class provide listening of console keyboard input. * \details This class provide listening of console keyboard input.
* There is two ways to receive pressed key: * There is two ways to receive pressed key:
* * external static function with format "void func(char key, void * data_)" * * 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) for (int i = 0; i < PRIVATE->ret; ++i)
PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' '; PICout(0) << PICoutManipulators::Hex << int(((uchar * )&rc)[i]) << ' ';
PICout(0) << "\n"; PICout(0) << "\n";
std::cout << PRIVATE->ret << " chars ";
for (int i = 0; i < PRIVATE->ret; ++i) for (int i = 0; i < PRIVATE->ret; ++i)
cout << "'" << (char)(rc[i]) << "' "; std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
cout << endl;*/ std::cout << std::endl;*/
if (rc[0] == 0) {piMSleep(10); return;} if (rc[0] == 0) {piMSleep(10); return;}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {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); int mod(0);
// 2 - shift 1 // 2 - shift 1
// 3 - alt 2 // 3 - alt 2

View File

@@ -1,6 +1,9 @@
/*! @file pikbdlistener.h /*! \file pikbdlistener.h
* @brief Keyboard console input listener * \ingroup Console
*/ * \~\brief
* \~english Keyboard console input listener
* \~russian Консольный захват клавиатуры
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Keyboard grabber for console Keyboard grabber for console
@@ -25,7 +28,7 @@
#include "pithread.h" #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 class PIP_EXPORT PIKbdListener: public PIThread
@@ -181,20 +184,20 @@ public:
//! \{ //! \{
//! \fn void enableExitCapture(int key = 'Q') //! \fn void enableExitCapture(int key = 'Q')
//! @brief Enable exit key "key" awaiting //! \brief Enable exit key "key" awaiting
//! \fn void disableExitCapture() //! \fn void disableExitCapture()
//! @brief Disable exit key awaiting //! \brief Disable exit key awaiting
//! \fn void setActive(bool yes = true) //! \fn void setActive(bool yes = true)
//! @brief Set keyboard listening is active or not //! \brief Set keyboard listening is active or not
//! \} //! \}
//! \events //! \events
//! \{ //! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) //! \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 /*! \file piscreen.h
* @brief Console GUI class * \ingroup Console
*/ * \~\brief
* \~english Console tiling manager
* \~russian Консольный тайловый менеджер
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Console GUI Console GUI
@@ -80,23 +83,23 @@ public:
//! \{ //! \{
//! \fn void waitForFinish() //! \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) //! \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) //! \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 //! \events
//! \{ //! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data) //! \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) //! \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 /*! \file piscreenconsole.h
* @brief Tile for PIScreen with PIConsole API * \ingroup Console
* * \~\brief
* This file declares TileVars * \~english Tile for PIScreen with PIConsole API
*/ * \~russian Тайл для PIScreen с API PIConsole
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Tile for PIScreen with PIConsole API Tile for PIScreen with PIConsole API

View File

@@ -1,6 +1,9 @@
/*! @file piscreendrawer.h /*! \file piscreendrawer.h
* @brief Drawer for PIScreen * \ingroup Console
*/ * \~\brief
* \~english Drawer for PIScreen
* \~russian Отрисовщик для PIScreen
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Drawer for PIScreen Drawer for PIScreen

View File

@@ -1,6 +1,9 @@
/*! @file piscreentile.h /*! \file piscreentile.h
* @brief Basic PIScreen tile * \ingroup Console
*/ * \~\brief
* \~english Basic PIScreen tile
* \~russian Базовый тайл для PIScreen
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Basic PIScreen tile Basic PIScreen tile

View File

@@ -1,6 +1,9 @@
/*! @file piscreentiles.h /*! \file piscreentiles.h
* @brief Various tiles for PIScreen * \ingroup Console
*/ * \~\brief
* \~english Various tiles for PIScreen
* \~russian Различные тайлы для PIScreen
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Various tiles for PIScreen Various tiles for PIScreen

View File

@@ -1,6 +1,9 @@
/*! @file piscreentypes.h /*! \file piscreentypes.h
* @brief Types for PIScreen * \ingroup Console
*/ * \~\brief
* \~english Types for PIScreen
* \~russian Типы для PIScreen
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Types for PIScreen Types for PIScreen

View File

@@ -1,6 +1,9 @@
/*! @file piterminal.h /*! \file piterminal.h
* @brief Virtual terminal * \ingroup Console
*/ * \~\brief
* \~english Virtual terminal
* \~russian Виртуальный терминал
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Virtual terminal 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 //! \addtogroup Containers
* @brief Base for generic containers //! \{
* //! \file picontainers.h
* This file declare all containers and useful macros //! \brief
* to use them //! \~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 PIP - Platform Independent Primitives
Base for generic containers Base macros for generic containers
Ivan Pelipenko peri4ko@yandex.ru Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -37,87 +45,140 @@
#include <type_traits> #include <type_traits>
#include <string.h> #include <string.h>
#include <new> #include <new>
#ifndef PIP_MEMALIGN_BYTES #include <algorithm>
# define PIP_MEMALIGN_BYTES (sizeof(void*)*4) #include <functional>
#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
template <typename C> template <typename C>
struct _reverse_wrapper { class _PIReverseWrapper {
C & c_; public:
_reverse_wrapper(C & c): c_(c) {} _PIReverseWrapper(C & c): c_(c) {}
_reverse_wrapper(const C & c): c_(const_cast<C&>(c)) {} _PIReverseWrapper(const C & c): c_(const_cast<C&>(c)) {}
typename C::reverse_iterator begin() {return c_.rbegin();} typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); } typename C::reverse_iterator end() {return c_.rend(); }
typename C::const_reverse_iterator begin() const {return c_.rbegin();} typename C::const_reverse_iterator begin() const {return c_.rbegin();}
typename C::const_reverse_iterator end() const {return c_.rend(); } typename C::const_reverse_iterator end() const {return c_.rend(); }
private:
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 #endif // PICONTAINERS_H

View File

@@ -1,6 +1,6 @@
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Module includes Containers
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify 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 You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \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 #ifndef PICONTAINERSMODULE_H
#define PICONTAINERSMODULE_H #define PICONTAINERSMODULE_H
@@ -28,4 +188,5 @@
#include "pistack.h" #include "pistack.h"
#include "pivector2d.h" #include "pivector2d.h"
#endif // PICONTAINERSMODULE_H #endif // PICONTAINERSMODULE_H

View File

@@ -1,8 +1,17 @@
/*! @file pideque.h //! \addtogroup Containers
* @brief Dynamic array of any type //! \{
* //! \file pideque.h
* This file declares PIDeque //! \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 PIP - Platform Independent Primitives
Dynamic array of any type Dynamic array of any type
@@ -28,39 +37,165 @@
#include "picontainers.h" #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> template <typename T>
class PIDeque { class PIDeque {
public: 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) { inline PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) 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) { inline PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) 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); 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) { 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)) 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()); 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) { 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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(size, true); alloc_forward(size);
newT(pid_data + pid_start, data, pid_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)) 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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
resize(piv_size, f); 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) { 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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
other._reset(); other._reset();
} }
inline virtual ~PIDeque() { inline virtual ~PIDeque() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize)) PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
@@ -69,161 +204,931 @@ public:
_reset(); _reset();
} }
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIDeque<T> & operator =(const PIDeque<T> & other) { inline PIDeque<T> & operator =(const PIDeque<T> & other) {
if (this == &other) return *this; if (this == &other) return *this;
deleteT(pid_data + pid_start, pid_size); 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); newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
return *this; return *this;
} }
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIDeque<T> & operator =(PIDeque<T> && other) { inline PIDeque<T> & operator =(PIDeque<T> && other) {
swap(other); swap(other);
return *this; return *this;
} }
typedef T value_type;
enum ReshapeOrder {
byRow,
byColumn
};
class iterator { class iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: 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; PIDeque<T> * parent;
size_t pos; ssize_t pos;
public: 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 iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];} inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {++pos;} inline T & operator ->() {return (*parent)[pos];}
inline void operator ++(int) {++pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator --() {--pos;}
inline void operator --(int) {--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);}
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 { class const_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: 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; const PIDeque<T> * parent;
size_t pos; ssize_t pos;
public: 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_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {++pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator ++(int) {++pos;}
inline void operator --() {--pos;} inline const_iterator & operator ++() {
inline void operator --(int) {--pos;} ++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);}
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 { class reverse_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: 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; PIDeque<T> * parent;
size_t pos; ssize_t pos;
public: 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 reverse_iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];} inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;} inline T & operator ->() {return (*parent)[pos];}
inline void operator ++(int) {--pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator --() {++pos;}
inline void operator --(int) {++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);}
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 { class const_reverse_iterator {
friend class PIDeque<T>; friend class PIDeque<T>;
private: 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; const PIDeque<T> * parent;
size_t pos; ssize_t pos;
public: 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_reverse_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator ++(int) {--pos;}
inline void operator --() {++pos;} inline const_reverse_iterator & operator ++() {
inline void operator --(int) {++pos;} --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);}
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);} 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 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);} 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);} 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 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 rbegin() const {return const_reverse_iterator(this, pid_size - 1);}
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -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;} 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;} 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;} 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 capacity() const {return pid_rsize;}
inline size_t _start() const {return pid_start;} 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 bool isEmpty() const {return (pid_size == 0);}
inline T & operator [](size_t index) {return pid_data[pid_start + index];} //! \~english Checks if the container has elements.
inline const T & operator [](size_t index) const {return pid_data[pid_start + index];} //! \~russian Проверяет не пуст ли контейнер.
inline const T & at(size_t index) const {return pid_data[pid_start + index];} //! \~\return
inline T & back() {return pid_data[pid_start + pid_size - 1];} //! \~english **true** if the container is not empty, **false** otherwise
inline const T & back() const {return pid_data[pid_start + pid_size - 1];} //! \~russian **true** если контейнер не пуст, **false** иначе.
inline T & front() {return pid_data[pid_start];} //! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline const T & front() const {return pid_data[pid_start];} inline bool isNotEmpty() const {return (pid_size > 0);}
inline bool operator ==(const PIDeque<T> & t) const {
if (pid_size != t.pid_size) return false; //! \~english Tests whether at least one element in the array
for (size_t i = 0; i < pid_size; ++i) //! passes the test implemented by the provided function `test`.
if (t[i] != (*this)[i]) //! \~russian Проверяет, удовлетворяет ли какой-либо элемент массива условию,
return false; //! заданному в передаваемой функции `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; return true;
} }
inline bool operator !=(const PIDeque<T> & t) const {return !(*this == t);}
inline bool operator >(const PIDeque<T> & t) const { //! \~english Full access to element by `index`.
if (pid_size != t.pid_size) return pid_size > t.pid_size; //! \~russian Полный доступ к элементу по индексу `index`.
for (size_t i = 0; i < pid_size; ++i) //! \~\details
if (t[i] != (*this)[i]) return t[i] > (*this)[i]; //! \~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; return false;
} }
inline bool contains(const T & v) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) //! \~english Count elements equal `e` in the array.
if (v == pid_data[i]) //! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
return true; //! \~\details
return false; //! \~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,
inline int etries(const T & v) const { //! 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; int ec = 0;
for (size_t i = pid_start; i < pid_start + pid_size; ++i) if (start < 0) {
if (v == pid_data[i]) ++ec; 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; return ec;
} }
inline ssize_t indexOf(const T & v) const {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) //! \~english Count elements in the array passes the test implemented by the provided function `test`.
if (v == pid_data[i]) //! \~russian Подсчитывает количество элементов в массиве,
return i - pid_start; //! проходящих по условию, заданному в передаваемой функции `test`.
return -1; //! \~\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) //! \~english Returns the first index at which a given element `e`
if (v == pid_data[i]) //! 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 i - pid_start;
}
}
return -1; 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]);} 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]);} 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< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -241,65 +1146,121 @@ public:
return *this; 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); deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, 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); elementNew(pid_data + i, e);
}
return *this; 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); deleteT(pid_data + pid_start, pid_size);
PIINTROSPECTION_CONTAINER_USED(T, 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)); elementNew(pid_data + i, f(i));
}
return *this; 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< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , 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); resize(new_size);
return fill(f); return fill(e);
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , 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); _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) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2; pid_start = (pid_rsize - pid_size) / 2;
}
} }
if (new_size > pid_size) { if (new_size > pid_size) {
size_t os = pid_size; size_t os = pid_size;
alloc(new_size, true); alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) 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); elementNew(pid_data + i, e);
}
} }
return *this; 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) { if (new_size < pid_size) {
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size); deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size; pid_size = new_size;
if (new_size == 0) if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2; pid_start = (pid_rsize - pid_size) / 2;
}
} }
if (new_size > pid_size) { if (new_size > pid_size) {
size_t os = pid_size; size_t os = pid_size;
alloc(new_size, true); alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) 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)); elementNew(pid_data + i, f(i));
}
} }
return *this; return *this;
} }
@@ -314,72 +1275,161 @@ public:
if (new_size < pid_size) { if (new_size < pid_size) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size-new_size)); PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size-new_size));
} }
alloc(new_size, true); alloc_forward(new_size);
return *this; 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) { inline PIDeque<T> & reserve(size_t new_size) {
if (new_size <= pid_rsize) return *this; if (new_size <= pid_rsize) return *this;
size_t os = pid_size; size_t os = pid_size;
alloc(new_size, true); alloc_forward(new_size);
pid_size = os; pid_size = os;
return *this; return *this;
} }
inline PIDeque<T> & insert(size_t index, const T & v = T()) { //! \~english Inserts value `e` at `index` position in the array.
if (index == pid_size) return push_back(v); //! \~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) PIINTROSPECTION_CONTAINER_USED(T, 1)
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false); bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) { if (dir) {
alloc(pid_size + 1, true); alloc_forward(pid_size + 1);
if (index < pid_size - 1) { if (index < pid_size - 1) {
size_t os = pid_size - index - 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)); memmove((void*)(&(pid_data[index + pid_start + 1])), (const void*)(&(pid_data[index + pid_start])), os * sizeof(T));
} }
} else { } else {
alloc(pid_size + 1, false, -1); alloc_backward(pid_size + 1, -1);
if (index > 0) if (index > 0) {
memmove((void*)(&(pid_data[pid_start])), (const void*)(&(pid_data[pid_start + 1])), index * sizeof(T)); memmove((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)); elementNew(pid_data + pid_start + index, e);
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);
return *this; 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) { inline PIDeque<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this; if (count == 0) return *this;
if (index + count >= pid_size) { if (index + count >= pid_size) {
@@ -389,15 +1439,24 @@ public:
size_t os = pid_size - index - count; size_t os = pid_size - index - count;
deleteT(&(pid_data[index + pid_start]), count); deleteT(&(pid_data[index + pid_start]), count);
if (os <= index) { 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 { } 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_start += count;
} }
pid_size -= count; pid_size -= count;
return *this; 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) { inline void swap(PIDeque<T> & other) {
piSwap<T*>(pid_data, other.pid_data); piSwap<T*>(pid_data, other.pid_data);
piSwap<size_t>(pid_size, other.pid_size); piSwap<size_t>(pid_size, other.pid_size);
@@ -405,13 +1464,114 @@ public:
piSwap<ssize_t>(pid_start, other.pid_start); piSwap<ssize_t>(pid_start, other.pid_start);
} }
typedef int (*CompareFunc)(const T * , const T * ); //! \~english Sorts the elements in non-descending order.
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);} //! \~russian Сортировка элементов в порядке возрастания.
inline PIDeque<T> & sort(CompareFunc compare = compare_func) { //! \~\details
piqsort(pid_data + pid_start, pid_size, sizeof(T), (int(*)(const void * , const void * ))compare); //! \~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; 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) { inline PIDeque<T> & enlarge(llong pid_size) {
llong ns = size_s() + pid_size; llong ns = size_s() + pid_size;
if (ns <= 0) clear(); if (ns <= 0) clear();
@@ -419,139 +1579,708 @@ public:
return *this; return *this;
} }
inline PIDeque<T> & removeOne(const T & v) { //! \~english Remove no more than one element equal `e`.
for (size_t i = 0; i < pid_size; ++i) //! \~russian Удаляет первый элемент, который равен элементу `e`.
if (pid_data[i + pid_start] == v) { //! \~\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); remove(i);
return *this; return *this;
} }
}
return *this; return *this;
} }
inline PIDeque<T> & removeAll(const T & v) {
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) //! \~english Remove all elements equal `e`.
if (pid_data[i + pid_start] == v) { //! \~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); remove(i);
--i; --i;
} }
}
return *this; return *this;
} }
inline PIDeque<T> & push_back(const T & v) { //! \~english Remove all elements in the array
alloc(pid_size + 1, true); //! passes the test implemented by the provided function `test`.
PIINTROSPECTION_CONTAINER_USED(T, 1); //! \~russian Удаляет все элементы, удовлетворяющие условию,
elementNew(pid_data + pid_start + pid_size - 1, v); //! заданному в передаваемой функции `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; 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); 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; 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));} //! \~english Appends the given element `e` to the end of the array.
inline PIDeque<T> & append(const PIDeque<T> & t) { //! \~russian Добавляет элемент `e` в конец массива.
assert(&t != this); //! \~\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; size_t ps = pid_size;
alloc(pid_size + t.pid_size, true); alloc_forward(pid_size + init_list.size());
newT(pid_data + ps + pid_start, t.pid_data + t.pid_start, t.pid_size); newT(pid_data + pid_start + ps, init_list.begin(), init_list.size());
return *this; 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;} //! \~english Appends the given array `v` to the end of the array.
inline PIDeque<T> & push_front(T && v) {insert(0, std::move(v)); return *this;} //! \~russian Добавляет массив `v` в конец массива.
inline PIDeque<T> & prepend(const T & v) {return push_front(v);} //! \~\details
inline PIDeque<T> & prepend(T && v) {return push_front(std::move(v));} //! \~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;} //! \~english Appends the given element `e` to the end of the array.
inline PIDeque<T> & pop_front() {if (pid_size == 0) return *this; remove(0); return *this;} //! \~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;} //! \~english Appends the given element `e` to the end of the array.
inline T take_front() {T t(front()); pop_front(); return t;} //! \~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> template <typename ST>
PIDeque<ST> toType() const { inline PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size); 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]); ret[i] = ST(pid_data[i + pid_start]);
}
return ret; return ret;
} }
const PIDeque<T> & forEach(std::function<void(const T &)> f) const { //! \~english Returns a new array with all elements
for (uint i = 0; i < pid_size; ++i) //! that pass the test implemented by the provided function `test`.
f(pid_data[i + pid_start]); //! \~russian Возвращает новый массив со всеми элементами,
return *this; //! прошедшими проверку, задаваемую в передаваемой функции `test`.
} //! \~\details
PIDeque<T> copyForEach(std::function<T(const T &)> f) const { //! \~\code
PIDeque<T> ret; ret.reserve(pid_size); //! PIDeque<int> v{3, 2, 5, 2, 7};
for (uint i = 0; i < pid_size; ++i) //! PIDeque<int> v2 = v.filter([](const int & i){return i > 2;});
ret << f(pid_data[i + pid_start]); //! 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; return ret;
} }
PIDeque<T> & forEachInplace(std::function<T(const T &)> f) {
for (uint i = 0; i < pid_size; ++i) //! \~english Execute function `void f(const T & e)` for every element in array.
pid_data[i + pid_start] = f(pid_data[i + pid_start]); //! \~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; 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> 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); PIDeque<ST> ret; ret.reserve(pid_size);
for (uint i = 0; i < pid_size; ++i) for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret << f(pid_data[i + pid_start]); ret << f(pid_data[i]);
}
return ret; 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; PIDeque<PIDeque<T>> ret;
if (isEmpty()) return 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); assert(rows*cols == pid_size);
ret.resize(rows); ret.resize(rows);
if (order == byRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols); ret[r] = PIDeque<T>(&(pid_data[r*cols]), cols);
}
} }
if (order == byColumn) { if (order == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols); ret[r].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]; ret[r][c] = pid_data[c*rows + r];
}
} }
} }
return ret; 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< template<typename C, typename std::enable_if<
std::is_same<T, PIDeque<C>>::value std::is_same<T, PIDeque<C>>::value
, int>::type = 0> , int>::type = 0>
inline PIDeque<C> reshape(int order = byRow) const { inline PIDeque<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> ret; PIDeque<C> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
size_t rows = size(); size_t rows = size();
size_t cols = at(0).size(); size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == byRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret.append(at(r)); ret.append(at(r));
}
} }
if (order == byColumn) { if (order == ReshapeByColumn) {
for (size_t c = 0; c < cols; c++) for (size_t c = 0; c < cols; c++) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret << at(r)[c]; ret << at(r)[c];
}
}
} }
ret.resize(rows * cols); ret.resize(rows * cols);
return ret; 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: private:
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;} inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
inline size_t asize(ssize_t s) { inline size_t asize(ssize_t s) {
if (s <= 0) return 0; 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; return pid_rsize + pid_rsize;
ssize_t t = 0, s_ = s - 1; }
ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
while (s_ >> t) while (s_ >> t)
++t; ++t;
return (1 << t); return (1 << t);
@@ -577,8 +2306,9 @@ private:
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) { if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
}
} }
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
@@ -615,7 +2345,7 @@ private:
if ((uchar*)pid_data != 0) free((uchar*)pid_data); if ((uchar*)pid_data != 0) free((uchar*)pid_data);
pid_data = 0; pid_data = 0;
} }
inline void checkMove(bool direction) { inline void checkMove() {
if (pid_size >= 4) { if (pid_size >= 4) {
if (pid_size < pid_rsize / 6) { if (pid_size < pid_rsize / 6) {
if (pid_start < ssize_t(pid_size + pid_size) || pid_start > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) { 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 inline void alloc_forward(size_t new_size) { // direction == true -> alloc forward
if (direction) {
if (pid_start + new_size <= pid_rsize) { if (pid_start + new_size <= pid_rsize) {
pid_size = new_size; pid_size = new_size;
checkMove(direction); checkMove();
return; return;
} }
pid_size = new_size; pid_size = new_size;
@@ -646,16 +2375,23 @@ private:
if (as != pid_rsize) { if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize)) PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T))); T * 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); assert(p_d);
pid_data = p_d; pid_data = p_d;
pid_rsize = as; pid_rsize = as;
} }
} else { }
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
size_t as; size_t as;
if (pid_start + start_offset < 0) if (pid_start + start_offset < 0) {
as = asize(pid_rsize - start_offset); as = asize(pid_rsize - start_offset);
else as = pid_rsize; } else {
as = pid_rsize;
}
if (as > pid_rsize) { if (as > pid_rsize) {
T * td = (T*)(malloc(as * sizeof(T))); T * td = (T*)(malloc(as * sizeof(T)));
ssize_t ns = pid_start + as - pid_rsize; ssize_t ns = pid_start + as - pid_rsize;
@@ -670,8 +2406,7 @@ private:
} }
pid_start += start_offset; pid_start += start_offset;
pid_size = new_size; pid_size = new_size;
checkMove(direction); checkMove();
}
} }
T * pid_data; T * pid_data;
@@ -681,10 +2416,24 @@ private:
#ifdef PIP_STD_IOSTREAM #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> 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 #endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename T> template<typename T>
inline PICout operator <<(PICout s, const PIDeque<T> & v) { inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s.space(); s.space();
@@ -692,15 +2441,15 @@ inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s << "{"; s << "{";
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
s << v[i]; s << v[i];
if (i < v.size() - 1) if (i < v.size() - 1) s << ", ";
s << ", ";
} }
s << "}"; s << "}";
s.restoreControl(); s.restoreControl();
return s; 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 #endif // PIDEQUE_H

View File

@@ -1,5 +1,5 @@
/** \class PIMap /** \class PIMap
* @brief Associative array * \brief Associative array
* \details This class used to store Key = Value array of any * \details This class used to store Key = Value array of any
* type of data. \a value() returns value for key and leave map * type of data. \a value() returns value for key and leave map
* unchaged in any case. \a operator [] create entry in map if * unchaged in any case. \a operator [] create entry in map if
@@ -9,97 +9,97 @@
* \a makeIterator() and \a makeReverseIterator(). * \a makeIterator() and \a makeReverseIterator().
* \fn PIMap::PIMap(); * \fn PIMap::PIMap();
* @brief Contructs an empty map * \brief Contructs an empty map
* \fn PIMap::PIMap(const PIMap & other); * \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); * \fn PIMap & PIMap::operator =(const PIMap & other);
* @brief Copy operator * \brief Copy operator
* \fn PIMap::PIMap(const PIMap & other); * \fn PIMap::PIMap(const PIMap & other);
* @brief Contructs a copy of "other" * \brief Contructs a copy of "other"
* \fn PIMapIterator PIMap::makeIterator() const * \fn PIMapIterator PIMap::makeIterator() const
* @brief Returns PIMapIterator for this map * \brief Returns PIMapIterator for this map
* \fn PIMapIterator PIMap::makeReverseIterator() const * \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 * \fn size_t PIMap::size() const
* @brief Returns entries count * \brief Returns entries count
* \fn int PIMap::size_s() const * \fn int PIMap::size_s() const
* @brief Returns entries count * \brief Returns entries count
* \fn size_t PIMap::length() const * \fn size_t PIMap::length() const
* @brief Returns entries count * \brief Returns entries count
* \fn bool PIMap::isEmpty() const * \fn bool PIMap::isEmpty() const
* @brief Returns if map is empty * \brief Returns if map is empty
* \fn T & PIMap::operator [](const Key & key) * \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 * \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) * \fn T & PIMap::at(const Key & key)
* @brief Equivalent to operator [] * \brief Equivalent to operator []
* \fn const T PIMap::at(const Key & key) const * \fn const T PIMap::at(const Key & key) const
* @brief Equivalent to operator [] * \brief Equivalent to operator []
* \fn PIMap & PIMap::operator <<(const PIMap & other) * \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 * \fn bool PIMap::operator ==(const PIMap & t) const
* @brief Compare operator * \brief Compare operator
* \fn bool PIMap::operator !=(const PIMap & t) const * \fn bool PIMap::operator !=(const PIMap & t) const
* @brief Compare operator * \brief Compare operator
* \fn bool PIMap::contains(const Key & key) const * \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) * \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) * \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) * \fn PIMap & PIMap::remove(const Key & key)
* @brief Equivalent \a removeOne(key) * \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::erase(const Key & key) * \fn PIMap & PIMap::erase(const Key & key)
* @brief Equivalent \a removeOne(key) * \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::clear() * \fn PIMap & PIMap::clear()
* @brief Clear map * \brief Clear map
* \fn void PIMap::swap(PIMap & other) * \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) * \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()) * \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 * \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 * \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 * \fn PIVector<Key> PIMap::keys() const
* @brief Returns all keys as PIVector * \brief Returns all keys as PIVector
* */ * */
@@ -107,7 +107,7 @@
/** \class PIMapIterator /** \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. * \details This class used to access keys and values in PIMap.
* You can use constructor to create iterator, or use \a PIMap::makeIterator() * You can use constructor to create iterator, or use \a PIMap::makeIterator()
* and \a PIMap::makeReverseIterator() methods. * and \a PIMap::makeReverseIterator() methods.
@@ -164,24 +164,24 @@
* \endcode * \endcode
* \fn PIMapIterator(const PIMap & map, bool reverse = false) * \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 * \fn const Key & PIMapIterator::key() const
* @brief Returns current entry key * \brief Returns current entry key
* \fn const T & PIMapIterator::value() const * \fn const T & PIMapIterator::value() const
* @brief Returns current entry value * \brief Returns current entry value
* \fn T & PIMapIterator::valueRef() const * \fn T & PIMapIterator::valueRef() const
* @brief Returns reference to current entry value * \brief Returns reference to current entry value
* \fn bool PIMapIterator::hasNext() * \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() * \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() * \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 /*! \file pimap.h
* @brief Associative array with custom types of key and value * \brief Associative array with custom types of key and value
* *
* This file declares PIMap * This file declares PIMap
*/ */
@@ -30,41 +30,6 @@
#include "pipair.h" #include "pipair.h"
template<class T>
void piQuickSort(T * a, ssize_t N) {
if (N < 1) return;
if (N < 46) {
T tmp;
ssize_t i,j;
for(i=1; i<=N; i++) {
tmp = a[i];
j = i-1;
while(tmp<a[j] && j>=0) {
a[j+1] = a[j];
j = j-1;
}
a[j+1] = tmp;
}
} else {
ssize_t i = 0, j = N;
T & p(a[N >> 1]);
do {
while (a[i] < p) i++;
while (a[j] > p) j--;
if (i <= j) {
if (i != j) {
//piCout << "swap" << i << j << a[i] << a[j];
piSwap<T>(a[i], a[j]);
}
i++; j--;
}
} while (i <= j);
if (j > 0) piQuickSort(a, j);
if (N > i) piQuickSort(a + i, N - i);
}
}
template <typename Key, typename T> template <typename Key, typename T>
class PIMapIterator; class PIMapIterator;
@@ -75,16 +40,19 @@ class PIMap {
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v); template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend class PIMapIterator; template <typename Key1, typename T1> friend class PIMapIterator;
public: public:
PIMap() {;} PIMap() {}
PIMap(const PIMap<Key, T> & other) {*this = other;} PIMap(const PIMap<Key, T> & other) {*this = other;}
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {} PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)) {}
PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
for (auto i: init_list)
insert(std::get<0>(i), std::get<1>(i));
}
virtual ~PIMap() {;} virtual ~PIMap() {;}
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) { PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
if (this == &other) return *this; if (this == &other) return *this;
clear(); clear();
pim_content = other.pim_content; pim_content = other.pim_content;
pim_index = other.pim_index;
return *this; return *this;
} }
@@ -107,6 +75,7 @@ public:
iterator(): parent(0), pos(0) {} iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);} const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(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 ++() {++pos;}
void operator ++(int) {++pos;} void operator ++(int) {++pos;}
void operator --() {--pos;} void operator --() {--pos;}
@@ -125,6 +94,7 @@ public:
reverse_iterator(): parent(0), pos(0) {} reverse_iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);} const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(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 ++() {--pos;}
void operator ++(int) {--pos;} void operator ++(int) {--pos;}
void operator --() {++pos;} void operator --() {++pos;}
@@ -197,38 +167,45 @@ public:
T & operator [](const Key & key) { T & operator [](const Key & key) {
bool f(false); bool f(false);
ssize_t i = _find(key, f); ssize_t i = _find(key, f);
if (f) return pim_content[pim_index[i].index]; if (!f) pim_content.insert(i, PIPair<Key, T>(key, T()));
pim_content.push_back(T()); return pim_content[i].second;
pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); }
return pim_content.back(); const T operator [](const Key & key) const {
bool f(false);
ssize_t i = _find(key, f);
if (f) return pim_content[i].second;
return T();
} }
const T operator [](const Key & key) const {bool f(false); ssize_t i = _find(key, f); if (f) return pim_content[pim_index[i].index]; return T();}
const T at(const Key & key) const {return (*this)[key];} const T at(const Key & key) const {return (*this)[key];}
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) { 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); assert(&other != this);
if (other.isEmpty()) return *this; if (other.isEmpty()) return *this;
if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;} // if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}
if (other.size() == 2) {insert(other.pim_index[0].key, other.pim_content[0]); insert(other.pim_index[1].key, other.pim_content[1]); return *this;} // if (other.size() == 2) {insert(other.pim_index[0].key, other.pim_content[0]); insert(other.pim_index[1].key, other.pim_content[1]); return *this;}
for (int i = 0; i < other.pim_index.size_s(); ++i) for (int i = 0; i < other.pim_content.size_s(); ++i)
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]); insert(other.pim_content[i].first, other.pim_content[i].second);
return *this; return *this;
} }
bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content && pim_index == t.pim_index);} bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content);}
bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content || pim_index != t.pim_index);} bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content);}
bool contains(const Key & key) const {bool f(false); _find(key, f); return f;} bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;} PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size);return *this;}
PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;} PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);} PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);} PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
PIMap<Key, T> & clear() {pim_content.clear(); pim_index.clear(); return *this;} PIMap<Key, T> & clear() {pim_content.clear(); return *this;}
void swap(PIMap<Key, T> & other) { void swap(PIMap<Key, T> & other) {
pim_content.swap(other.pim_content); pim_content.swap(other.pim_content);
pim_index.swap(other.pim_index);
} }
PIMap<Key, T> & insert(const Key & key, const T & value) { PIMap<Key, T> & insert(const Key & key, const T & value) {
@@ -236,10 +213,9 @@ public:
ssize_t i = _find(key, f); ssize_t i = _find(key, f);
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value; //piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
if (f) { if (f) {
pim_content[pim_index[i].index] = value; pim_content[i].second = value;
} else { } else {
pim_content.push_back(value); pim_content.insert(i, PIPair<Key, T>(key, value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
} }
return *this; return *this;
} }
@@ -248,20 +224,34 @@ public:
ssize_t i = _find(key, f); ssize_t i = _find(key, f);
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value; //piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
if (f) { if (f) {
pim_content[pim_index[i].index] = std::move(value); pim_content[i].second = std::move(value);
} else { } else {
pim_content.push_back(std::move(value)); // pim_content.push_back(std::move(value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1)); // pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
pim_content.insert(i, PIPair<Key, T>(key, std::move(value)));
} }
return *this; return *this;
} }
const T value(const Key & key, const T & default_ = T()) const {bool f(false); ssize_t i = _find(key, f); if (!f) return default_; return pim_content[pim_index[i].index];} const T value(const Key & key, const T & default_ = T()) const {
PIVector<T> values() const {return pim_content;} bool f(false);
Key key(const T & value_, const Key & default_ = Key()) const {for (int i = 0; i < pim_index.size_s(); ++i) if (pim_content[pim_index[i].index] == value_) return pim_index[i].key; return default_;} ssize_t i = _find(key, f);
if (!f) return default_;
return pim_content[i].second;
}
PIVector<T> values() const {
PIVector<T> ret;
for (size_t i = 0; i < pim_content.size(); ++i) ret << pim_content[i].second;
return ret;
}
Key key(const T & value_, const Key & default_ = Key()) const {
for (int i = 0; i < pim_content.size_s(); ++i)
if (pim_content[i].second == value_)
return pim_content[i].first;
return default_;
}
PIVector<Key> keys() const { PIVector<Key> keys() const {
PIVector<Key> ret; PIVector<Key> ret;
for (int i = 0; i < pim_index.size_s(); ++i) for (size_t i = 0; i < pim_content.size(); ++i) ret << pim_content[i].first;
ret << pim_index[i].key;
return ret; return ret;
} }
@@ -269,66 +259,53 @@ public:
piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:"; piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:";
for (size_t i = 0; i < pim_content.size(); ++i) for (size_t i = 0; i < pim_content.size(); ++i)
piCout << PICoutManipulators::Tab << i << ":" << pim_content[i]; piCout << PICoutManipulators::Tab << i << ":" << pim_content[i];
piCout << "index:"; // piCout << "index:";
for (size_t i = 0; i < pim_index.size(); ++i) // for (size_t i = 0; i < pim_index.size(); ++i)
piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index; // piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
} }
protected: protected:
struct MapIndex { // struct MapIndex {
MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;} // MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;}
Key key; // Key key;
size_t index; // size_t index;
bool operator ==(const MapIndex & s) const {return key == s.key;} // bool operator ==(const MapIndex & s) const {return key == s.key;}
bool operator !=(const MapIndex & s) const {return key != s.key;} // bool operator !=(const MapIndex & s) const {return key != s.key;}
bool operator <(const MapIndex & s) const {return key < s.key;} // bool operator <(const MapIndex & s) const {return key < s.key;}
bool operator >(const MapIndex & s) const {return key > s.key;} // bool operator >(const MapIndex & s) const {return key > s.key;}
}; // };
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v); // template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v); // template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const { ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
ssize_t mid; ssize_t mid;
while (first <= last) { while (first <= last) {
mid = (first + last) / 2; mid = (first + last) / 2;
if (key > pim_index[mid].key) first = mid + 1; if (key > pim_content[mid].first) first = mid + 1;
else if (key < pim_index[mid].key) last = mid - 1; else if (key < pim_content[mid].first) last = mid - 1;
else {found = true; return mid;} else {found = true; return mid;}
} }
found = false; found = false;
return first; return first;
} }
void _sort() {piQuickSort<MapIndex>(pim_index.data(), pim_index.size_s() - 1);}
ssize_t _find(const Key & k, bool & found) const { ssize_t _find(const Key & k, bool & found) const {
if (pim_index.isEmpty()) { if (pim_content.isEmpty()) {
found = false; found = false;
return 0; return 0;
} }
return binarySearch(0, pim_index.size_s() - 1, k, found); return binarySearch(0, pim_content.size_s() - 1, k, found);
} }
void _remove(ssize_t index) { void _remove(ssize_t index) {
//if (index >= pim_index.size()) return; pim_content.remove(index);
size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
pim_index.remove(index);
for (size_t i = 0; i < pim_index.size(); ++i)
if (pim_index[i].index == bi) {
pim_index[i].index = ci;
break;
}
piSwap<T>(pim_content[ci], pim_content.back());
pim_content.resize(pim_index.size());
} }
const value_type _pair(ssize_t index) const { const value_type _pair(ssize_t index) const {
if (index < 0 || index >= pim_index.size_s()) if (index < 0 || index >= pim_content.size_s()) return value_type();
return value_type(); return pim_content[index];
//piCout << "_pair" << index << pim_index[index].index;
return value_type(pim_index[index].key, pim_content[pim_index[index].index]);
} }
Key & _key(ssize_t index) {return pim_index[index].key;} Key & _key(ssize_t index) {return pim_content[index].first;}
T & _value(ssize_t index) {return pim_content[pim_index[index].index];} T & _value(ssize_t index) {return pim_content[index].second;}
PIVector<T> pim_content; PIDeque<PIPair<Key, T>> pim_content;
PIDeque<MapIndex> pim_index;
}; };

View File

@@ -1,8 +1,17 @@
/*! @file pipair.h //! \addtogroup Containers
* @brief pair //! \{
* //! \file pipair.h
* This file declare PIPair //! \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 PIP - Platform Independent Primitives
pair pair
@@ -25,31 +34,111 @@
#ifndef PIPAIR_H #ifndef PIPAIR_H
#define 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> template<typename Type0, typename Type1>
class PIPair { class PIPair {
public: 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; Type0 first;
//! \~english Second element.
//! \~russian Второй элемент.
Type1 second; Type1 second;
}; };
//! \~english Compare operator with PIPair.
//! \~russian Оператор сравнения с PIPair.
template<typename Type0, typename Type1> 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> 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) {
template<typename Type0, typename Type1> 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 #ifdef PIP_STD_IOSTREAM
template<typename Type0, typename Type1> 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 #endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename Type0, typename Type1> 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 #endif // PIPAIR_H

View File

@@ -1,5 +1,5 @@
/*! @file pideque.h /*! \file piqueue.h
* @brief Queue container * \brief Queue container
* *
* This file declare PIQueue * This file declare PIQueue
*/ */

View File

@@ -1,5 +1,5 @@
/*! @file piset.h /*! \file piset.h
* @brief Set container * \brief Set container
* *
* This file declare PISet * This file declare PISet
*/ */
@@ -27,7 +27,7 @@
#include "pimap.h" #include "pimap.h"
/*! @brief Set of any type /*! \brief Set of any type
* \details This class used to store collection of unique elements * \details This class used to store collection of unique elements
* of any type. You can only add values to set with \a operator<< or * 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 * 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;} template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
//! \relatesalso PISet @brief Returns subtraction of two sets //! \relatesalso PISet \brief Returns subtraction of two sets
template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;} template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;}
//! \relatesalso PISet @brief Returns unite of two sets //! \relatesalso PISet \brief Returns unite of two sets
template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;} template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
//! \relatesalso PISet @brief Returns intersetion of two sets //! \relatesalso PISet \brief Returns intersetion of two sets
template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;} template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;}

View File

@@ -1,5 +1,5 @@
/*! @file pistack.h /*! \file pistack.h
* @brief Stack container * \brief Stack container
* *
* This file declare PIStack * 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 //! \addtogroup Containers
* @brief Dynamic array of any type //! \{
* //! \file pivector.h
* This file declares PIVector //! \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 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 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@@ -28,39 +37,165 @@
#include "picontainers.h" #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> template <typename T>
class PIVector { class PIVector {
public: 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) { inline PIVector(): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) 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) { inline PIVector(const T * data, size_t size): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(size); alloc(size);
newT(piv_data, data, piv_size); newT(piv_data, data, piv_size);
} }
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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(other.piv_size); alloc(v.piv_size);
newT(piv_data, other.piv_data, 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) { inline PIVector(std::initializer_list<T> init_list): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(init_list.size()); alloc(init_list.size());
newT(piv_data, init_list.begin(), init_list.size()); newT(piv_data, init_list.begin(), init_list.size());
} }
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)) 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)) 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)) PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
other._reset(); v._reset();
} }
inline virtual ~PIVector() { inline virtual ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T) PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize)) PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
@@ -69,156 +204,921 @@ public:
_reset(); _reset();
} }
inline PIVector<T> & operator =(const PIVector<T> & other) { //! \~english Assign operator.
if (this == &other) return *this; //! \~russian Оператор присваивания.
inline PIVector<T> & operator =(const PIVector<T> & v) {
if (this == &v) return *this;
clear(); clear();
deleteT(piv_data, piv_size); deleteT(piv_data, piv_size);
alloc(other.piv_size); alloc(v.piv_size);
newT(piv_data, other.piv_data, piv_size); newT(piv_data, v.piv_data, piv_size);
return *this; return *this;
} }
inline PIVector<T> & operator =(PIVector<T> && other) { //! \~english Assign move operator.
swap(other); //! \~russian Оператор перемещающего присваивания.
inline PIVector<T> & operator =(PIVector<T> && v) {
swap(v);
return *this; return *this;
} }
typedef T value_type;
enum ReshapeOrder {
byRow,
byColumn
};
class iterator { class iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: 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; PIVector<T> * parent;
size_t pos; ssize_t pos;
public: 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 iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];} inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {++pos;} inline T & operator ->() {return (*parent)[pos];}
inline void operator ++(int) {++pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator --() {--pos;}
inline void operator --(int) {--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);}
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 { class const_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: 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; const PIVector<T> * parent;
size_t pos; ssize_t pos;
public: 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_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {++pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator ++(int) {++pos;}
inline void operator --() {--pos;} inline const_iterator & operator ++() {
inline void operator --(int) {--pos;} ++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);}
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 { class reverse_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: 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; PIVector<T> * parent;
size_t pos; ssize_t pos;
public: 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 reverse_iterator(): parent(0), pos(0) {}
inline T & operator *() {return (*parent)[pos];} inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;} inline T & operator ->() {return (*parent)[pos];}
inline void operator ++(int) {--pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator --() {++pos;}
inline void operator --(int) {++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);}
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 { class const_reverse_iterator {
friend class PIVector<T>; friend class PIVector<T>;
private: 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; const PIVector<T> * parent;
size_t pos; ssize_t pos;
public: 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_reverse_iterator(): parent(0), pos(0) {}
inline const T & operator *() const {return (*parent)[pos];} inline const T & operator *() const {return (*parent)[pos];}
inline void operator ++() {--pos;} inline const T & operator ->() const {return (*parent)[pos];}
inline void operator ++(int) {--pos;}
inline void operator --() {++pos;} inline const_reverse_iterator & operator ++() {
inline void operator --(int) {++pos;} --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);}
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);} 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 iterator end() {return iterator(this, piv_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, piv_size);} 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);} 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 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 rbegin() const {return const_reverse_iterator(this, piv_size - 1);}
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -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;} 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;} 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;} 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;} 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 bool isEmpty() const {return (piv_size == 0);}
inline T & operator [](size_t index) {return piv_data[index];} //! \~english Checks if the container has elements.
inline const T & operator [](size_t index) const {return piv_data[index];} //! \~russian Проверяет не пуст ли контейнер.
inline const T & at(size_t index) const {return piv_data[index];} //! \~\return
inline T & back() {return piv_data[piv_size - 1];} //! \~english **true** if the container is not empty, **false** otherwise
inline const T & back() const {return piv_data[piv_size - 1];} //! \~russian **true** если контейнер не пуст, **false** иначе.
inline T & front() {return piv_data[0];} //! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline const T & front() const {return piv_data[0];} inline bool isNotEmpty() const {return (piv_size > 0);}
inline bool operator ==(const PIVector<T> & t) const {
if (piv_size != t.piv_size) //! \~english Tests whether at least one element in the array
return false; //! passes the test implemented by the provided function `test`.
for (size_t i = 0; i < piv_size; ++i) //! \~russian Проверяет, удовлетворяет ли какой-либо элемент массива условию,
if (t[i] != piv_data[i]) //! заданному в передаваемой функции `test`.
return false; //! \~\return
return true; //! \~english **true** if, in the array,
} //! it finds an element for which the provided function returns **true**;
inline bool operator !=(const PIVector<T> & t) const {return !(*this == t);} //! otherwise it returns **false**. Always returns **false** if is empty.
inline bool contains(const T & v) const { //! \~russian **true** если хотя бы для одного элемента
for (size_t i = 0; i < piv_size; ++i) //! передаваемая функция возвращает **true**, в остальных случаях **false**.
if (v == piv_data[i]) //! Метод возвращает **false** при любом условии для пустого массива.
return true; //! \~\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; 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; int ec = 0;
for (size_t i = 0; i < piv_size; ++i) if (start < 0) {
if (v == piv_data[i]) ++ec; 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; return ec;
} }
inline ssize_t indexOf(const T & v) const {
for (size_t i = 0; i < piv_size; ++i) //! \~english Count elements in the array passes the test implemented by the provided function `test`.
if (v == piv_data[i]) //! \~russian Подсчитывает количество элементов в массиве,
return i; //! проходящих по условию, заданному в передаваемой функции `test`.
return -1; //! \~\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) //! \~english Returns the first index at which a given element `e`
if (v == piv_data[i]) //! can be found in the array, or `-1` if it is not present.
return i; //! \~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; 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]);} 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]);} 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< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -235,21 +1135,50 @@ public:
return *this; 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); deleteT(piv_data, piv_size);
PIINTROSPECTION_CONTAINER_USED(T, 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); elementNew(piv_data + i, e);
}
return *this; 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); deleteT(piv_data, piv_size);
PIINTROSPECTION_CONTAINER_USED(T, 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)); elementNew(piv_data + i, f(i));
}
return *this; 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< template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value !std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -265,7 +1194,18 @@ public:
return fill(f); 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) { if (new_size < piv_size) {
T * de = &(piv_data[new_size]); T * de = &(piv_data[new_size]);
deleteT(de, piv_size - new_size); deleteT(de, piv_size - new_size);
@@ -275,12 +1215,25 @@ public:
size_t os = piv_size; size_t os = piv_size;
alloc(new_size); alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) 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); elementNew(piv_data + i, e);
}
} }
return *this; 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) { if (new_size < piv_size) {
T * de = &(piv_data[new_size]); T * de = &(piv_data[new_size]);
deleteT(de, piv_size - new_size); deleteT(de, piv_size - new_size);
@@ -290,11 +1243,13 @@ public:
size_t os = piv_size; size_t os = piv_size;
alloc(new_size); alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os)) 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)); elementNew(piv_data + i, f(i));
}
} }
return *this; return *this;
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value std::is_trivially_copyable<T1>::value
, int>::type = 0> , int>::type = 0>
@@ -308,10 +1263,25 @@ public:
alloc(new_size); alloc(new_size);
return *this; return *this;
} }
inline void _copyRaw(T * dst, const T * src, size_t size) { inline void _copyRaw(T * dst, const T * src, size_t size) {
newT(dst, src, size); newT(dst, src, size);
} }
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~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) { inline PIVector<T> & reserve(size_t new_size) {
if (new_size <= piv_rsize) return *this; if (new_size <= piv_rsize) return *this;
size_t os = piv_size; size_t os = piv_size;
@@ -320,37 +1290,97 @@ public:
return *this; 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); alloc(piv_size + 1);
if (index < piv_size - 1) { if (index < piv_size - 1) {
size_t os = piv_size - index - 1; size_t os = piv_size - index - 1;
memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T)); memmove((void*)(&(piv_data[index + 1])), (const void*)(&(piv_data[index])), os * sizeof(T));
} }
PIINTROSPECTION_CONTAINER_USED(T, 1) PIINTROSPECTION_CONTAINER_USED(T, 1)
elementNew(piv_data + index, v); elementNew(piv_data + index, e);
return *this;
}
inline PIVector<T> & insert(size_t index, T && v) {
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);
return *this; 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) { inline PIVector<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this; if (count == 0) return *this;
if (index + count >= piv_size) { if (index + count >= piv_size) {
@@ -364,170 +1394,820 @@ public:
return *this; return *this;
} }
inline void swap(PIVector<T> & other) { //! \~english Swaps array `v` other with this array.
piSwap<T*>(piv_data, other.piv_data); //! \~russian Меняет местами массив `v` с этим массивом.
piSwap<size_t>(piv_size, other.piv_size); //! \~\details
piSwap<size_t>(piv_rsize, other.piv_rsize); //! \~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 * ); //! \~english Sorts the elements in non-descending order.
static int compare_func(const T * t0, const T * t1) {return (*t0) < (*t1) ? -1 : ((*t0) == (*t1) ? 0 : 1);} //! \~russian Сортировка элементов в порядке возрастания.
inline PIVector<T> & sort(CompareFunc compare = compare_func) { //! \~\details
piqsort(piv_data, piv_size, sizeof(T), (int(*)(const void * , const void * ))compare); //! \~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; return *this;
} }
inline PIVector<T> & enlarge(llong piv_size) { //! \~english Sorts the elements in non-descending order.
llong ns = size_s() + piv_size; //! \~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(); if (ns <= 0) clear();
else resize(size_t(ns)); else resize(size_t(ns), e);
return *this; return *this;
} }
inline PIVector<T> & removeOne(const T & v) { //! \~english Remove no more than one element equal `e`.
for (size_t i = 0; i < piv_size; ++i) //! \~russian Удаляет первый элемент, который равен элементу `e`.
if (piv_data[i] == v) { //! \~\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); remove(i);
return *this; return *this;
} }
}
return *this; return *this;
} }
inline PIVector<T> & removeAll(const T & v) {
for (ssize_t i = 0; i < ssize_t(piv_size); ++i) //! \~english Remove all elements equal `e`.
if (piv_data[i] == v) { //! \~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); remove(i);
--i; --i;
} }
}
return *this; return *this;
} }
inline PIVector<T> & push_back(const T & v) { //! \~english Remove all elements in the array
alloc(piv_size + 1); //! passes the test implemented by the provided function `test`.
PIINTROSPECTION_CONTAINER_USED(T, 1); //! \~russian Удаляет все элементы, удовлетворяющие условию,
elementNew(piv_data + piv_size - 1, v); //! заданному в передаваемой функции `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; 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); alloc(piv_size + 1);
PIINTROSPECTION_CONTAINER_USED(T, 1); PIINTROSPECTION_CONTAINER_USED(T, 1);
elementNew(piv_data + piv_size - 1, std::move(v)); elementNew(piv_data + piv_size - 1, e);
return *this; 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));} //! \~english Appends the given element `e` to the end of the array.
inline PIVector<T> & append(const PIVector<T> & other) { //! \~russian Добавляет элемент `e` в конец массива.
assert(&other != this); //! \~\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; size_t ps = piv_size;
alloc(piv_size + other.piv_size); alloc(piv_size + init_list.size());
newT(piv_data + ps, other.piv_data, other.piv_size); newT(piv_data + ps, init_list.begin(), init_list.size());
return *this; 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;} //! \~english Appends the given array `v` to the end of the array.
inline PIVector<T> & push_front(T && v) {insert(0, std::move(v)); return *this;} //! \~russian Добавляет массив `v` в конец массива.
inline PIVector<T> & prepend(const T & v) {return push_front(v);} //! \~\details
inline PIVector<T> & prepend(T && v) {return push_front(std::move(v));} //! \~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() { inline PIVector<T> & pop_back() {
if (piv_size == 0) if (piv_size == 0) return *this;
return *this;
resize(piv_size - 1); resize(piv_size - 1);
return *this; 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() { inline PIVector<T> & pop_front() {
if (piv_size == 0) if (piv_size == 0) return *this;
return *this;
remove(0); remove(0);
return *this; return *this;
} }
inline T take_back() {T t(back()); pop_back(); return t;} //! \~english Remove one element from the end of the array and return it.
inline T take_front() {T t(front()); pop_front(); return t;} //! \~russian Удаляет один элемент с начала массива и возвращает его.
//! \~\details
template <typename ST> //! \~\code
PIVector<ST> toType() const { //! PIVector<int> v{1, 2, 3};
PIVector<ST> ret(piv_size); //! piCout << v.take_back(); // 3
for (uint i = 0; i < piv_size; ++i) //! piCout << v; // {1, 2}
ret[i] = ST(piv_data[i]); //! \endcode
return ret; //! \~\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 { //! \~english Remove one element from the begining of the array and return it.
for (uint i = 0; i < piv_size; ++i) //! \~russian Удаляет один элемент с конца массива и возвращает его.
f(piv_data[i]); //! \~\details
return *this; //! \~\code
} //! PIVector<int> v{1, 2, 3};
PIVector<T> copyForEach(std::function<T(const T &)> f) const { //! piCout << v.take_front(); // 1
PIVector<T> ret; ret.reserve(piv_size); //! piCout << v; // {2, 3}
for (uint i = 0; i < piv_size; ++i) //! \endcode
ret << f(piv_data[i]); //! \~\sa \a take_front(), \a pop_back(), \a pop_front()
return ret; inline T take_front() {
} T e(front());
PIVector<T> & forEachInplace(std::function<T(const T &)> f) { pop_front();
for (uint i = 0; i < piv_size; ++i) return e;
piv_data[i] = f(piv_data[i]);
return *this;
} }
//! \~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> 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); PIVector<ST> ret; ret.reserve(piv_size);
for (uint i = 0; i < piv_size; ++i) for (size_t i = 0; i < piv_size; ++i) {
ret << f(piv_data[i]); ret << ST(piv_data[i]);
}
return ret; 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; PIVector<PIVector<T>> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
assert(rows*cols == piv_size);
ret.resize(rows); ret.resize(rows);
if (order == byRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret[r] = PIVector<T>(&(piv_data[r*cols]), cols); ret[r] = PIVector<T>(&(piv_data[r*cols]), cols);
}
} }
if (order == byColumn) { if (order == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) { for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols); ret[r].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]; ret[r][c] = piv_data[c*rows + r];
}
} }
} }
return ret; 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< template<typename C, typename std::enable_if<
std::is_same<T, PIVector<C>>::value std::is_same<T, PIVector<C>>::value
, int>::type = 0> , int>::type = 0>
inline PIVector<C> reshape(int order = byRow) const { inline PIVector<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIVector<C> ret; PIVector<C> ret;
if (isEmpty()) return ret; if (isEmpty()) return ret;
size_t rows = size(); size_t rows = size();
size_t cols = at(0).size(); size_t cols = at(0).size();
ret.reserve(rows * cols); ret.reserve(rows * cols);
if (order == byRow) { if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret.append(at(r)); ret.append(at(r));
}
} }
if (order == byColumn) { if (order == ReshapeByColumn) {
for (size_t c = 0; c < cols; c++) for (size_t c = 0; c < cols; c++) {
for (size_t r = 0; r < rows; r++) for (size_t r = 0; r < rows; r++) {
ret << at(r)[c]; ret << at(r)[c];
}
}
} }
ret.resize(rows * cols); ret.resize(rows * cols);
return ret; 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: private:
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;} inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
inline size_t asize(size_t s) { inline size_t asize(size_t s) {
if (s == 0) return 0; 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; 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); return (1 << t);
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
@@ -551,8 +2231,9 @@ private:
inline void deleteT(T * d, size_t sz) { inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz) PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if ((uchar*)d != 0) { if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]); elementDelete(d[i]);
}
} }
} }
template<typename T1 = T, typename std::enable_if< template<typename T1 = T, typename std::enable_if<
@@ -599,6 +2280,11 @@ private:
if (as == piv_rsize) return; if (as == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize)) PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T))); T * 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); assert(p_d);
piv_data = p_d; piv_data = p_d;
piv_rsize = as; piv_rsize = as;
@@ -609,12 +2295,24 @@ private:
}; };
#ifdef PIP_STD_IOSTREAM #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> 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 #endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename T> template<typename T>
inline PICout operator <<(PICout s, const PIVector<T> & v) { inline PICout operator <<(PICout s, const PIVector<T> & v) {
s.space(); s.space();
@@ -622,15 +2320,16 @@ inline PICout operator <<(PICout s, const PIVector<T> & v) {
s << "{"; s << "{";
for (size_t i = 0; i < v.size(); ++i) { for (size_t i = 0; i < v.size(); ++i) {
s << v[i]; s << v[i];
if (i < v.size() - 1) if (i < v.size() - 1) {
s << ", "; s << ", ";
}
} }
s << "}"; s << "}";
s.restoreControl(); s.restoreControl();
return s; 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 #endif // PIVECTOR_H

View File

@@ -1,5 +1,5 @@
/*! @file pivector2d.h /*! \file pivector2d.h
* @brief 2D wrapper around PIVector * \brief 2D wrapper around PIVector
* *
* This file declares PIVector * This file declares PIVector
*/ */
@@ -27,7 +27,7 @@
#include "pivector.h" #include "pivector.h"
/*! @brief 2D array, /*! \brief 2D array,
* \details This class used to store 2D array of any type elements as plain vector. * \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. * 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. * 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(); 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); mat.forEach(f);
return *this;
} }
PIVector2D<T> copyForEach(std::function<T(const T &)> f) const {
PIVector2D<T> ret(*this); PIVector2D<T> & forEach(std::function<void(T &)> f) {
ret.mat = mat.copyForEach(f); mat.forEach(f);
return ret;
}
PIVector2D<T> & forEachInplace(std::function<T(const T &)> f) {
mat.forEachInplace(f);
return *this; return *this;
} }

View File

@@ -1,8 +1,16 @@
/*! @file pibase.h /*! \file pibase.h
* @brief Base types and functions * \ingroup Core
* \~\brief
* \~english Base types and functions
* \~russian Базовые типы и методы
* *
* \~\details
* \~english
* This file implements first layer above the system and * This file implements first layer above the system and
* declares some basic useful functions * declares some basic useful functions
* \~russian
* Этот файл реализует первый слой после системы и объявляет
* несколько базовых полезных методов
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -30,97 +38,175 @@
#include "piplatform.h" #include "piplatform.h"
#include "pip_export.h" #include "pip_export.h"
#include "pip_defs.h" #include "pip_defs.h"
#include "string.h" #include <string.h>
//! \~english
//! Meta-information section for any entity. //! Meta-information section for any entity.
//! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo. //! Parsing by \a pip_cmg and can be accessed by \a PICodeInfo.
//! Contains sequence of key=value pairs, e.g. //! Contains sequence of key=value pairs, e.g.
//! \~russian
//! Секция метаинформации для любой сущности.
//! Парсится \a pip_cmg и доступна с помощью \a PICodeInfo.
//! Содержит набор пар ключ=значение, например
//! \~
//! PIMETA(id=12345,tag="my string") //! PIMETA(id=12345,tag="my string")
#define PIMETA(...) #define PIMETA(...)
#ifdef DOXYGEN #ifdef DOXYGEN
//! Major value of PIP version //! \~\brief
//! \~english Major value of PIP version
//! \~russian Мажорная версия PIP
# define PIP_VERSION_MAJOR # define PIP_VERSION_MAJOR
//! Minor value of PIP version //! \~\brief
//! \~english Minor value of PIP version
//! \~russian Минорная версия PIP
# define PIP_VERSION_MINOR # define PIP_VERSION_MINOR
//! Revision value of PIP version //! \~\brief
//! \~english Revision value of PIP version
//! \~russian Ревизия версии PIP
# define PIP_VERSION_REVISION # define PIP_VERSION_REVISION
//! Suffix of PIP version //! \~\brief
//! \~english Suffix of PIP version
//! \~russian Суффикс версии PIP
# define PIP_VERSION_SUFFIX # 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 # 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 # 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 # 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 # define QNX
//! Macro is defined when host is Blackberry //! \~\brief
//! \~english Macro is defined when operation system is Blackberry
//! \~russian Макрос объявлен когда операционная система Blackberry
# define 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 # 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 # define MAC_OS
//! Macro is defined when host is Android //! \~\brief
//! \~english Macro is defined when operation system is Android
//! \~russian Макрос объявлен когда операционная система Android
# define 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 # 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 # 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 # 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 # 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 # 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 # 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) # 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) # 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) # define PRIVATE_DEFINITION_END(Class)
//! Macro to access private section by pointer //! \~\brief
//! \~english Macro to access private section by pointer
//! \~russian Макрос для доступа к частной секции
# define PRIVATE # 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 # define PRIVATEWB
//! Macro to start static initializer //! \~\brief
//! \~english Macro to start static initializer
//! \~russian Макрос для начала статической инициализации
# define STATIC_INITIALIZER_BEGIN # define STATIC_INITIALIZER_BEGIN
//! Macro to end static initializer //! \~\brief
//! \~english Macro to end static initializer
//! \~russian Макрос для окончания статической инициализации
# define STATIC_INITIALIZER_END # define STATIC_INITIALIZER_END
#undef MICRO_PIP
#undef FREERTOS
#endif //DOXYGEN #endif //DOXYGEN
#ifdef CC_AVR_GCC
# include <ArduinoSTL.h>
#endif
#include <functional> #include <functional>
#include <cstddef> #include <cstddef>
#include <cassert>
#include <limits>
#include <atomic>
#ifdef WINDOWS #ifdef WINDOWS
# ifdef CC_VC # ifdef CC_VC
# define SHUT_RDWR 2 # define SHUT_RDWR 2
@@ -139,6 +225,8 @@
extern long long __pi_perf_freq; extern long long __pi_perf_freq;
#endif #endif
#ifndef DOXYGEN
#ifdef ANDROID #ifdef ANDROID
///# define tcdrain(fd) ioctl(fd, TCSBRK, 1) ///# define tcdrain(fd) ioctl(fd, TCSBRK, 1)
//inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;} //inline int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;}
@@ -158,10 +246,10 @@
extern char ** environ; extern char ** environ;
#endif #endif
#ifdef NDEBUG #ifndef NO_UNUSED
# undef NDEBUG # define NO_UNUSED(x) (void)x
#endif #endif
#include <cassert>
#ifndef assert #ifndef assert
# define assert(x) # define assert(x)
# define assertm(exp, msg) # define assertm(exp, msg)
@@ -169,6 +257,12 @@
# define assertm(exp, msg) assert(((void)msg, exp)) # define assertm(exp, msg) assert(((void)msg, exp))
#endif #endif
#ifdef MICRO_PIP
# define __PIP_TYPENAME__(T) "?"
#else
# define __PIP_TYPENAME__(T) typeid(T).name()
#endif
#ifdef CC_GCC #ifdef CC_GCC
# undef DEPRECATED # undef DEPRECATED
# define DEPRECATED __attribute__((deprecated)) # define DEPRECATED __attribute__((deprecated))
@@ -221,7 +315,7 @@
# define DEPRECATED # define DEPRECATED
#endif #endif
#endif //DOXYGEN
// Private data macros // Private data macros
#ifndef DOXYGEN #ifndef DOXYGEN
@@ -274,28 +368,47 @@
} _PIP_ADD_COUNTER(_pip_initializer_); } _PIP_ADD_COUNTER(_pip_initializer_);
#ifdef FREERTOS //! \~\brief
# define PIP_MIN_MSLEEP 10. //! \~english Minimal sleep in milliseconds for internal PIP using
#else //! \~russian Минимальное значание задержки в милисекундах для внутреннего использования в библиотеке PIP
# define PIP_MIN_MSLEEP 1. //! \~\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 #endif
//! Macro used for infinite loop //! \~\brief
//! \~english Macro used for infinite loop
//! \~russian Макрос для бесконечного цикла
#define FOREVER for (;;) #define FOREVER for (;;)
//! Macro used for infinite wait //! \~\brief
#define FOREVER_WAIT FOREVER msleep(PIP_MIN_MSLEEP); //! \~english Macro used for infinite wait
//! \~russian Макрос для бесконечного ожидания
#define FOREVER_WAIT FOREVER piMinSleep();
//! Macro used for infinite wait //! \~\brief
#define WAIT_FOREVER FOREVER msleep(PIP_MIN_MSLEEP); //! \~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; 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 //! for function PIInit::mountInfo(), default is 10000 ms
//! \~russian Глобальная переменная минимального ожидания между реальным обновлением
//! в методе PIInit::mountInfo(), по умолчанию 10000 мс
extern PIP_EXPORT double piMountInfoRefreshIntervalMs; extern PIP_EXPORT double piMountInfoRefreshIntervalMs;
typedef unsigned char uchar; typedef unsigned char uchar;
@@ -306,12 +419,20 @@ typedef unsigned long long ullong;
typedef long long llong; typedef long long llong;
typedef long double ldouble; typedef long double ldouble;
/*! @brief Templated function for swap two values //! \~\brief
* \details Example:\n \snippet piincludes.cpp swap */ //! \~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);} 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 "=" //! \~\brief
* \details Example:\n \snippet piincludes.cpp swapBinary */ //! \~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) { template<typename T> inline void piSwapBinary(T & f, T & s) {
if ((size_t*)&f == (size_t*)&s) return; if ((size_t*)&f == (size_t*)&s) return;
size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T); size_t j = (sizeof(T) / sizeof(size_t)), bs = j * sizeof(size_t), bf = sizeof(T);
@@ -346,8 +467,12 @@ template<> inline void piSwapBinary(const void *& f, const void *& s) {
} }
/*! @brief Function for compare two values without "=" by raw content //! \~\brief
* \details Example:\n \snippet piincludes.cpp compareBinary */ //! \~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) { inline bool piCompareBinary(const void * f, const void * s, size_t size) {
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
if (((const uchar*)f)[i] != ((const uchar*)s)[i]) if (((const uchar*)f)[i] != ((const uchar*)s)[i])
@@ -355,152 +480,323 @@ inline bool piCompareBinary(const void * f, const void * s, size_t size) {
return true; return true;
} }
/*! @brief Templated function return round of float falue //! \~\brief
* \details Round is the nearest integer value \n //! \~english Templated function return round of float falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий округленное значение
* - \c piRoundf for "float" //! \~\details
* - \c piRoundd for "double" //! \~english
* //! Round is the nearest integer value \n
* Example: //! There are some macros:
* \snippet piincludes.cpp round */ //! - \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));} 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 //! \~\brief
* \details Floor is the largest integer that is not greater than value \n //! \~english Templated function return floor of float falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий floor значение
* - \c piFloorf for "float" //! \~\details
* - \c piFloord for "double" //! \~english
* //! Floor is the largest integer that is not greater than "v" \n
* Example: //! There are some macros:
* \snippet piincludes.cpp floor */ //! - \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);} 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 //! \~\brief
* \details Ceil is the smallest integer that is not less than value \n //! \~english Templated function return ceil of float falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий ceil значение
* - \c piCeilf for "float" //! \~\details
* - \c piCeild for "double" //! \~english
* //! Ceil is the smallest integer that is not less than "v" \n
* Example: //! There are some macros:
* \snippet piincludes.cpp ceil */ //! - \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;} 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 //! \~\brief
* \details Absolute is the positive or equal 0 value \n //! \~english Templated function return absolute of numeric falue
* There are some macros: //! \~russian Шаблонный метод, возвращающий модуль числового значения
* - \c piAbss for "short" //! \~\details
* - \c piAbsi for "int" //! \~english
* - \c piAbsl for "long" //! Absolute is the positive or equal 0 value \n
* - \c piAbsll for "llong" //! There are some macros:
* - \c piAbsf for "float" //! - \c piAbss for "short"
* - \c piAbsd for "double" //! - \c piAbsi for "int"
* //! - \c piAbsl for "long"
* Example: //! - \c piAbsll for "llong"
* \snippet piincludes.cpp abs */ //! - \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);} template<typename T> inline constexpr T piAbs(const T & v) {return (v >= T(0) ? v : -v);}
/*! @brief Templated function return minimum of two values //! \~\brief
* \details There are some macros: //! \~english Templated function return minimum of two values
* - \c piMins for "short" //! \~russian Шаблонный метод, возвращающий минимум из двух значений
* - \c piMini for "int" //! \~\details
* - \c piMinl for "long" //! \~english
* - \c piMinll for "llong" //! There are some macros:
* - \c piMinf for "float" //! - \c piMins for "short"
* - \c piMind for "double" //! - \c piMini for "int"
* //! - \c piMinl for "long"
* Example: //! - \c piMinll for "llong"
* \snippet piincludes.cpp min2 */ //! - \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);} 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 //! \~\brief
* \details There are some macros: //! \~english Templated function return minimum of tree values
* - \c piMins for "short" //! \~russian Шаблонный метод, возвращающий минимум из трех значений
* - \c piMini for "int" //! \~\details
* - \c piMinl for "long" //! \~english
* - \c piMinll for "llong" //! There are some macros:
* - \c piMinf for "float" //! - \c piMins for "short"
* - \c piMind for "double" //! - \c piMini for "int"
* //! - \c piMinl for "long"
* Example: //! - \c piMinll for "llong"
* \snippet piincludes.cpp min3 */ //! - \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));} 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 //! \~\brief
* \details There are some macros: //! \~english Templated function return maximum of two values
* - \c piMaxs for "short" //! \~russian Шаблонный метод, возвращающий максимум из двух значений
* - \c piMaxi for "int" //! \~\details
* - \c piMaxl for "long" //! \~english
* - \c piMaxll for "llong" //! There are some macros:
* - \c piMaxf for "float" //! - \c piMaxs for "short"
* - \c piMaxd for "double" //! - \c piMaxi for "int"
* //! - \c piMaxl for "long"
* Example: //! - \c piMaxll for "llong"
* \snippet piincludes.cpp max2 */ //! - \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);} 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 //! \~\brief
* \details There are some macros: //! \~english Templated function return maximum of tree values
* - \c piMaxs for "short" //! \~russian Шаблонный метод, возвращающий максимум из трех значений
* - \c piMaxi for "int" //! \~\details
* - \c piMaxl for "long" //! \~english
* - \c piMaxll for "llong" //! There are some macros:
* - \c piMaxf for "float" //! - \c piMaxs for "short"
* - \c piMaxd for "double" //! - \c piMaxi for "int"
* //! - \c piMaxl for "long"
* Example: //! - \c piMaxll for "llong"
* \snippet piincludes.cpp max3 */ //! - \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));} 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 //! \~\brief
* \details Clamped is the not greater than "max" and not lesser than "min" value \n //! \~english Templated function return clamped value
* There are some macros: //! \~russian Шаблонный метод, возвращающий ограниченное значение
* - \c piClamps for "short" //! \~\details
* - \c piClampi for "int" //! \~english
* - \c piClampl for "long" //! Clamped is the not greater than "max" and not lesser than "min" value \n
* - \c piClampll for "llong" //! There are some macros:
* - \c piClampf for "float" //! - \c piClamps for "short"
* - \c piClampd for "double" //! - \c piClampi for "int"
* //! - \c piClampl for "long"
* Example: //! - \c piClampll for "llong"
* \snippet piincludes.cpp clamp */ //! - \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));} 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) { inline void piLetobe(void * data, int size) {
for (int i = 0; i < size / 2; i++) for (int i = 0; i < size / 2; i++)
piSwap<uchar>(((uchar*)data)[size - i - 1], ((uchar*)data)[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));} template<typename T> inline void piLetobe(T * v) {piLetobe(v, sizeof(T));}
/*! @brief Templated function that returns "v" with inversed byte order //! \~\brief
* \details This function used to convert values between little and big endian \n //! \~english Templated function that returns "v" with inversed byte order
* There are some macros: //! \~russian Шаблонный метод, возвращающий переменную "v" с измененным порядком байт
* - \c piLetobes for "ushort" //! \~\details
* - \c piLetobei for "uint" //! \~english
* - \c piLetobel for "ulong" //! This function used to convert values between little and big endian \n
* - \c piLetobell for "ullong" //! There are some macros:
* //! - \c piLetobes for "ushort"
* Example: //! - \c piLetobei for "uint"
* \snippet piincludes.cpp letobe */ //! - \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;} template<typename T> inline T piLetobe(const T & v) {T tv(v); piLetobe(&tv, sizeof(T)); return tv;}
// specialization // specialization
template<> inline ushort piLetobe(const ushort & v) {return (v << 8) | (v >> 8);} template<> inline uint16_t piLetobe(const uint16_t & 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 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) { template<> inline float piLetobe(const float & v) {
union _pletobe_f { union _pletobe_f {
_pletobe_f(const float &f_) {f = f_;} _pletobe_f(const float &f_) {f = f_;}
float f; float f;
uint v; uint32_t v;
}; };
_pletobe_f a(v); _pletobe_f a(v);
a.v = (a.v >> 24) | ((a.v >> 8) & 0xFF00) | ((a.v << 8) & 0xFF0000) | ((a.v << 24) & 0xFF000000); a.v = (a.v >> 24) | ((a.v >> 8) & 0xFF00) | ((a.v << 8) & 0xFF0000) | ((a.v << 24) & 0xFF000000);
return a.f; 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) { inline uint piHashData(const uchar * data, uint len, uint seed = 0) {
if (!data || len <= 0) return 0u; if (!data || len <= 0) return 0u;
uint h = seed; uint h = seed;
@@ -558,6 +854,8 @@ template<> inline uint piHash(const ldouble & v) {return piHashData((const uchar
#define piRoundf piRound<float> #define piRoundf piRound<float>
#define piRoundd piRound<double> #define piRoundd piRound<double>
#define piComparef piCompare<float>
#define piCompared piCompare<double>
#define piFloorf piFloor<float> #define piFloorf piFloor<float>
#define piFloord piFloor<double> #define piFloord piFloor<double>
#define piCeilf piCeil<float> #define piCeilf piCeil<float>

View File

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

View File

@@ -21,6 +21,77 @@
#include "pistringlist.h" #include "pistringlist.h"
#include <iostream> #include <iostream>
//! \class PIByteArray pibytearray.h
//! \~\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] = { static const uchar base64Table[64] = {
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
@@ -221,22 +292,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; uchar c = 0;
int sz = size_s(); int sz = size_s();
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i)
c += at(i); c += at(i);
c = ~(c + 1); if (inverse) c = ~(c + 1);
return c; 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; uint c = 0;
int sz = size_s(); int sz = size_s();
for (int i = 0; i < sz; ++i) for (int i = 0; i < sz; ++i)
c += at(i) * (i + 1); c += at(i) * (i + 1);
c = ~(c + 1); if (inverse) c = ~(c + 1);
return c; return c;
} }

View File

@@ -1,5 +1,8 @@
/*! @file pibytearray.h /*! \file pibytearray.h
* @brief Byte array * \ingroup Core
* \~\brief
* \~english Byte array
* \~russian Байтовый массив
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -27,85 +30,59 @@
#include "pibitarray.h" #include "pibitarray.h"
#include "pimap.h" #include "pimap.h"
#include "pivector2d.h" #include "pivector2d.h"
#include <stdio.h>
#ifdef FREERTOS
# define _TYPENAME_(T) "?"
#else
# define _TYPENAME_(T) typeid(T).name()
#endif
class PIString; class PIString;
class PIByteArray; class PIByteArray;
/*! @class PIByteArray //! \ingroup Core
* @brief The PIByteArray class provides an array of bytes //! \~\brief
* @details PIByteArray used to store raw bytes. //! \~english The %PIByteArray class provides an array of bytes.
* It can be constructed from any data and size. //! \~russian Класс %PIByteArray представляет собой массив байтов.
* 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> class PIP_EXPORT PIByteArray: public PIDeque<uchar>
{ {
public: public:
//! Constructs an empty byte array //! \~english Constructs an empty byte array
//! \~russian Создает пустой байтовый массив
PIByteArray() {;} PIByteArray() {;}
//! \~english Constructs copy of byte array "o"
//! \~russian Создает копию байтового массива "o"
PIByteArray(const PIByteArray & o): PIDeque<uchar>(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)) {} 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);} 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)) {} 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) {} 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 { struct RawData {
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v); friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v); friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
public: public:
//! Constructs data block //! \~english Constructs data block
//! \~russian Создает блок данных
RawData(void * data = 0, int size = 0) {d = data; s = size;} RawData(void * data = 0, int size = 0) {d = data; s = size;}
RawData(const RawData & o) {d = o.d; s = o.s;} 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(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;} RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
private: private:
@@ -113,16 +90,27 @@ public:
int s; 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;} 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(); 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(); PIByteArray & convertFromBase64();
//! Return converted to Base 64 data //! \~english Return converted to Base 64 data
//! \~russian Возвращает копию байтового массива, преобразованного в Base 64
PIByteArray toBase64() const; PIByteArray toBase64() const;
PIByteArray & compressRLE(uchar threshold = 192); PIByteArray & compressRLE(uchar threshold = 192);
@@ -130,36 +118,40 @@ public:
PIByteArray compressedRLE(uchar threshold = 192) {PIByteArray ba(*this); ba.compressRLE(threshold); return ba;} 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;} 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; 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. //! The hex encoding uses the numbers 0-9 and the letters a-f.
//! \~russian
//! Возвращает шестнадцатеричное представление массива, без пробелов.
//! Оно использует цифры 0-9 и буквы a-f.
PIString toHex() const; 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;} 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;} 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;} PIByteArray & append(uchar t) {push_back(t); return *this;}
//! Returns 8-bit checksum //! \~english Returns 8-bit checksum
//! sum all bytes, add 1, inverse //! \~russian Возвращает 8-битную контрольную сумму
//! Pseudocode: uchar checksumPlain8(bool inverse = true) const;
//! sum += at(i);
//! return ~(sum + 1)
uchar checksumPlain8() const;
//! Returns 32-bit checksum //! \~english Returns 32-bit checksum
//! sum all bytes multiplyed by index+1, add 1, inverse //! \~russian Возвращает 32-битную контрольную сумму
//! Pseudocode: uint checksumPlain32(bool inverse = true) const;
//! sum += at(i) * (i + 1);
//! return ~(sum + 1)
uint checksumPlain32() const;
//! Returns hash //! \~english Returns hash of content
//! \~russian Возвращает хэш содержимого
uint hash() const; uint hash() const;
void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());} void operator =(const PIDeque<uchar> & d) {resize(d.size()); memcpy(data(), d.data(), d.size());}
@@ -172,7 +164,8 @@ public:
static PIByteArray fromHex(PIString str); 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 PIByteArray & base64);
static PIByteArray fromBase64(const PIString & base64); static PIByteArray fromBase64(const PIString & base64);
@@ -187,43 +180,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) { inline bool operator <(const PIByteArray & v0, const PIByteArray & v1) {
if (v0.size() == v1.size()) { if (v0.size() == v1.size()) {
for (uint i = 0; i < v0.size(); ++i) if (v0.isEmpty()) return false;
if (v0[i] != v1[i]) return memcmp(v0.data(), v1.data(), v0.size()) < 0;
return v0[i] < v1[i];
return false;
} }
return v0.size() < v1.size(); return v0.size() < v1.size();
} }
//! \relatesalso PIByteArray @brief Byte arrays compare operator //! \relatesalso PIByteArray
inline bool operator ==(PIByteArray & f, PIByteArray & s) { //! \~english Byte arrays compare operator
if (f.size_s() != s.size_s()) //! \~russian Оператор сравнения
return false; inline bool operator >(const PIByteArray & v0, const PIByteArray & v1) {
for (int i = 0; i < f.size_s(); ++i) if (v0.size() == v1.size()) {
if (f[i] != s[i]) if (v0.isEmpty()) return false;
return false; return memcmp(v0.data(), v1.data(), v0.size()) > 0;
return true; }
return v0.size() > v1.size();
} }
//! \relatesalso PIByteArray @brief Byte arrays compare operator //! \relatesalso PIByteArray
inline bool operator !=(PIByteArray & f, PIByteArray & s) { //! \~english Byte arrays compare operator
if (f.size_s() != s.size_s()) //! \~russian Оператор сравнения
return true; inline bool operator ==(const PIByteArray & v0, const PIByteArray & v1) {
for (int i = 0; i < f.size_s(); ++i) if (v0.size() == v1.size()) {
if (f[i] != s[i]) if (v0.isEmpty()) return true;
return true; return memcmp(v0.data(), v1.data(), v0.size()) == 0;
}
return false; 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 #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); inline std::ostream & operator <<(std::ostream & s, const PIByteArray & ba);
#endif #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); PIP_EXPORT PICout operator <<(PICout s, const PIByteArray & ba);
@@ -232,16 +240,24 @@ PIP_EXPORT PICout operator <<(PICout s, const PIByteArray & ba);
// store operators for basic types // 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;} 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;} 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;} 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> 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) { inline PIByteArray::StreamRef operator <<(PIByteArray & s, const T & v) {
int os = s.size_s(); int os = s.size_s();
@@ -250,10 +266,14 @@ inline PIByteArray::StreamRef operator <<(PIByteArray & s, const T & v) {
return s; 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); 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
//! \~russian Оператор сохранения
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) { inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {
int os = s.size_s(); int os = s.size_s();
if (v.s > 0) { if (v.s > 0) {
@@ -263,7 +283,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v
return s; 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, template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0, 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> typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
@@ -285,7 +307,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
return s; 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, template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0, 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> typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
@@ -307,7 +331,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
return s; 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, template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0, 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> typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
@@ -328,10 +354,14 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
return s; 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;} 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> template<typename Type0, typename Type1>
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;} inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
@@ -341,20 +371,28 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v
// restore operators for basic types // 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;} 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;} 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;} 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> template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) { inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
if (s.size() < sizeof(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)); assert(s.size() >= sizeof(v));
} }
memcpy((void*)(&v), s.data(), sizeof(v)); memcpy((void*)(&v), s.data(), sizeof(v));
@@ -362,10 +400,14 @@ inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
return s; 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); PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);
//! \relatesalso PIByteArray @brief Restore operator, see \ref PIByteArray_sec1 for details //! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) { inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {
if (s.size_s() < v.s) { if (s.size_s() < v.s) {
printf("error with RawData %d < %d\n", (int)s.size_s(), v.s); printf("error with RawData %d < %d\n", (int)s.size_s(), v.s);
@@ -378,13 +420,15 @@ inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {
return s; 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, template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0, 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> 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) { inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) { 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); assert(s.size_s() >= 4);
} }
int sz; s >> sz; int sz; s >> sz;
@@ -400,7 +444,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> 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) { inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) { 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); assert(s.size_s() >= 4);
} }
int sz; s >> sz; int sz; s >> sz;
@@ -409,13 +453,15 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
return s; 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, template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0, 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> 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) { inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) { 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); assert(s.size_s() >= 4);
} }
int sz; s >> sz; int sz; s >> sz;
@@ -431,7 +477,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> 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) { inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) { 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); assert(s.size_s() >= 4);
} }
int sz; s >> sz; int sz; s >> sz;
@@ -440,13 +486,15 @@ inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
return s; 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, template<typename T,
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0, 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> 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) { inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) { 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); assert(s.size_s() >= 8);
} }
int r, c; s >> r >> c; int r, c; s >> r >> c;
@@ -463,7 +511,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> 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) { inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) { 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); assert(s.size_s() >= 8);
} }
int r,c; int r,c;
@@ -473,10 +521,14 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
return s; 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;} 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> template<typename Type0, typename Type1>
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;} inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
@@ -486,7 +538,9 @@ inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >
// store operators for complex types // 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> 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) { inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
s << int(v.size_s()); s << int(v.size_s());
@@ -494,7 +548,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
return s; 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> 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) { inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
s << int(v.size_s()); s << int(v.size_s());
@@ -502,7 +558,9 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
return s; 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> 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) { inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
s << int(v.rows()) << int(v.cols()) << v.toPlainVector(); s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
@@ -515,11 +573,13 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
// restore operators for complex types // 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> template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) { inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
if (s.size_s() < 4) { 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); assert(s.size_s() >= 4);
} }
int sz; s >> sz; int sz; s >> sz;
@@ -528,11 +588,13 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
return s; 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> template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) { inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
if (s.size_s() < 4) { 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); assert(s.size_s() >= 4);
} }
int sz; s >> sz; int sz; s >> sz;
@@ -541,11 +603,13 @@ inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
return s; 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> template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) { inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
if (s.size_s() < 8) { 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); assert(s.size_s() >= 8);
} }
int r,c; int r,c;
@@ -561,33 +625,39 @@ inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
// other types // other types
//! \relatesalso PIByteArray
//! \~english Store operator
//! \~russian Оператор сохранения
template <typename Key, typename T> template <typename Key, typename T>
inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) { inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
s << int(v.pim_index.size_s()); // s << int(v.pim_index.size_s());
for (uint i = 0; i < v.size(); ++i) // for (uint i = 0; i < v.size(); ++i)
s << int(v.pim_index[i].index) << v.pim_index[i].key; // s << int(v.pim_index[i].index) << v.pim_index[i].key;
s << v.pim_content; s << v.pim_content;
return s; return s;
} }
//! \relatesalso PIByteArray
//! \~english Restore operator
//! \~russian Оператор извлечения
template <typename Key, typename T> template <typename Key, typename T>
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) { inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
if (s.size_s() < 4) { 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); assert(s.size_s() >= 4);
} }
int sz; s >> sz; v.pim_index.resize(sz); // int sz; s >> sz; v.pim_index.resize(sz);
int ind = 0; // int ind = 0;
for (int i = 0; i < sz; ++i) { // for (int i = 0; i < sz; ++i) {
s >> ind >> v.pim_index[i].key; // s >> ind >> v.pim_index[i].key;
v.pim_index[i].index = ind; // v.pim_index[i].index = ind;
} // }
s >> v.pim_content; s >> v.pim_content;
if (v.pim_content.size_s() != v.pim_index.size_s()) { // if (v.pim_content.size_s() != v.pim_index.size_s()) {
piCout << "Warning: loaded invalid PIMap, clear"; // piCout << "Warning: loaded invalid PIMap, clear";
v.clear(); // v.clear();
} // }
return s; return s;
} }
@@ -606,16 +676,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();} 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);} 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) { template <typename T> PIByteArray piSerialize(const T & value) {
PIByteArray ret; PIByteArray ret;
ret << value; ret << value;
return ret; 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) { template <typename T> T piDeserialize(const PIByteArray & data) {
T ret; T ret;
if (!data.isEmpty()) { if (!data.isEmpty()) {
@@ -626,7 +709,4 @@ template <typename T> T piDeserialize(const PIByteArray & data) {
} }
#undef _TYPENAME_
#endif // PIBYTEARRAY_H #endif // PIBYTEARRAY_H

View File

@@ -1,6 +1,3 @@
/*! @file pichar.h
* @brief Unicode char
*/
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
Unicode char Unicode char
@@ -21,7 +18,7 @@
*/ */
#include "piincludes_p.h" #include "piincludes_p.h"
#include "pibytearray.h" #include "pistring.h"
#ifdef PIP_ICU #ifdef PIP_ICU
# define U_NOEXCEPT # define U_NOEXCEPT
# include "unicode/ucnv.h" # include "unicode/ucnv.h"
@@ -38,18 +35,17 @@ char * __utf8name__ = 0;
# include <ctype.h> # include <ctype.h>
#endif #endif
#include <wchar.h> #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 //! \class PIChar pichar.h
* @brief Unicode char //! \~\details
* \details This class is wrapper around \c "uint". //! \~english
* There are many contructors and information functions //! 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) { ushort charFromCodepage(const char * c, int size, const char * codepage, int * taken = 0) {
@@ -76,12 +72,14 @@ ushort charFromCodepage(const char * c, int size, const char * codepage, int * t
if (taken) *taken = ret; if (taken) *taken = ret;
return buffer; return buffer;
# else # else
wchar_t wc(0); mbstate_t state;
mbtowc(0, 0, 0); // reset mbtowc memset(&state, 0, sizeof(state));
ret = mbtowc(&wc, c, size); wchar_t wc;
ret = mbrtowc(&wc, c, size, &state);
//printf("mbtowc = %d\n", ret); //printf("mbtowc = %d\n", ret);
//piCout << errorString();
if (ret < 1) return 0; if (ret < 1) return 0;
return ushort(int(wc)); return ushort(wc);
# endif # endif
#endif #endif
return ushort(c[0]); return ushort(c[0]);
@@ -324,12 +322,12 @@ char PIChar::toSystem() const {
PIChar PIChar::toUpper() const { PIChar PIChar::toUpper() const {
if (isAscii()) return PIChar(toupper(ch)); if (isAscii()) return PIChar((ushort)toupper(ch));
#ifdef PIP_ICU #ifdef PIP_ICU
UChar c(0); UChar c(0);
UErrorCode e((UErrorCode)0); UErrorCode e((UErrorCode)0);
u_strToUpper(&c, 1, (const UChar*)(&ch), 1, 0, &e); u_strToUpper(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c); return PIChar((ushort)c);
#else #else
# ifdef WINDOWS # ifdef WINDOWS
ushort wc = 0; ushort wc = 0;
@@ -337,17 +335,17 @@ PIChar PIChar::toUpper() const {
return PIChar(wc); return PIChar(wc);
# endif # endif
#endif #endif
return PIChar(towupper(ch)); return PIChar((ushort)towupper(ch));
} }
PIChar PIChar::toLower() const { PIChar PIChar::toLower() const {
if (isAscii()) return PIChar(tolower(ch)); if (isAscii()) return PIChar((ushort)tolower(ch));
#ifdef PIP_ICU #ifdef PIP_ICU
UChar c(0); UChar c(0);
UErrorCode e((UErrorCode)0); UErrorCode e((UErrorCode)0);
u_strToLower(&c, 1, (const UChar*)(&ch), 1, 0, &e); u_strToLower(&c, 1, (const UChar*)(&ch), 1, 0, &e);
return PIChar(c); return PIChar((ushort)c);
#else #else
# ifdef WINDOWS # ifdef WINDOWS
ushort wc = 0; ushort wc = 0;
@@ -355,7 +353,7 @@ PIChar PIChar::toLower() const {
return PIChar(wc); return PIChar(wc);
# endif # endif
#endif #endif
return PIChar(towlower(ch)); return PIChar((ushort)towlower(ch));
} }
@@ -377,15 +375,9 @@ PICout operator <<(PICout s, const PIChar & v) {
} else } else
#endif #endif
#ifdef WINDOWS #ifdef WINDOWS
s << v.toSystem(); s << v.toSystem();
#else #else
{ s << PIString(v);
char tc[8];
wctomb(0, 0);
int sz = wctomb(tc, v.ch);
for (int b = 0; b < sz; ++b)
s << tc[b];
}
#endif #endif
} }
s.restoreControl(); s.restoreControl();

View File

@@ -1,5 +1,8 @@
/*! @file pichar.h /*! \file pichar.h
* @brief Unicode char * \ingroup Core
* \~\brief
* \~english Single string character
* \~russian Один символ строки
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -29,102 +32,147 @@ extern PIP_EXPORT char * __syslocname__;
extern PIP_EXPORT char * __sysoemname__; extern PIP_EXPORT char * __sysoemname__;
extern PIP_EXPORT char * __utf8name__; extern PIP_EXPORT char * __utf8name__;
//! \ingroup Core
//! \~\brief
//! \~english %PIChar represents a single character.
//! \~russian %PIChar представляет собой один символ строки.
class PIP_EXPORT PIChar class PIP_EXPORT PIChar
{ {
friend class PIString; friend class PIString;
friend PICout PIP_EXPORT operator <<(PICout s, const PIChar & v); friend PICout PIP_EXPORT operator <<(PICout s, const PIChar & v);
public: public:
//! Contructs ascii symbol //! \~english Contructs Ascii symbol
PIChar(const char c) {ch = c; ch &= 0xFF;} //! \~russian Создает символ Ascii
PIChar(char c) {ch = c; ch &= 0xFF;}
//! Contructs 2-bytes symbol //! \~english Contructs ascii symbol
PIChar(const short c) {ch = c;} //! \~russian Создает символ Ascii
PIChar(uchar c) {ch = c;}
//! Contructs 4-bytes symbol //! \~english Contructs 2-bytes symbol
PIChar(const int c) {ch = c;} //! \~russian Создает 2-байтный символ
PIChar(ushort c = 0) {ch = c;}
//! Contructs ascii symbol //! \~english Contructs 2-bytes symbol from `wchar_t`
PIChar(const uchar c) {ch = c; ch &= 0xFF;} //! \~russian Создает 2-байтный символ из `wchar_t`
PIChar(wchar_t c) {ch = c;}
//! Contructs 2-bytes symbol //! \~english Contructs symbol from system locale and no more than 4 bytes of string
PIChar(const ushort c) {ch = c;} //! \~russian Создает символ из системной локали не более 4 байт длины
//! Default constructor. Contructs 4-bytes symbol
PIChar(const uint c = 0) {ch = c;}
//! Contructs symbol from no more than 4 bytes of string
PIChar(const char * c, int * bytes = 0); PIChar(const char * c, int * bytes = 0);
//! Copy operator //! \~english Copy operator
//! \~russian Оператор присваивания
PIChar & operator =(const char v) {ch = v; return *this;} 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; bool operator ==(const PIChar & o) const;
//! Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const PIChar & o) const {return !(o == *this);} bool operator !=(const PIChar & o) const {return !(o == *this);}
//! Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const PIChar & o) const; bool operator >(const PIChar & o) const;
//! Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const PIChar & o) const; bool operator <(const PIChar & o) const;
//! Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const PIChar & o) const; bool operator >=(const PIChar & o) const;
//! Compare operator //! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const PIChar & o) const; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; bool isAscii() const;
const wchar_t * toWCharPtr() const; const wchar_t * toWCharPtr() const;
//! Return as <tt>"char * "</tt> string //! \~english Returns as `char *` string
//! \~russian Возвращает символ как указатель на `char *`
const char * toCharPtr() const; const char * toCharPtr() const;
wchar_t toWChar() const; wchar_t toWChar() const;
//! \~english Returns symbol as Ascii
//! \~russian Возвращает символ в Ascii
char toAscii() const {return ch % 256;} char toAscii() const {return ch % 256;}
//! \~english Returns symbol as console codepage
//! \~russian Возвращает символ в консольной кодировке
char toConsole1Byte() const; char toConsole1Byte() const;
//! \~english Returns symbol as system codepage
//! \~russian Возвращает символ в системной кодировке
char toSystem() const; char toSystem() const;
ushort unicode16Code() const {return ch;} ushort unicode16Code() const {return ch;}
//! Return symbol in upper case //! \~english Returns symbol in upper case
//! \~russian Возвращает символ в нижнем регистре
PIChar toUpper() const; PIChar toUpper() const;
//! Return symbol in lower case //! \~english Returns symbol in lower case
//! \~russian Возвращает символ в верхнем регистре
PIChar toLower() const; PIChar toLower() const;
//! \~english Returns symbol from console codepage
//! \~russian Возвращает символ из консольной кодировки
static PIChar fromConsole(char c); static PIChar fromConsole(char c);
//! \~english Returns symbol from system codepage
//! \~russian Возвращает символ из системной кодировки
static PIChar fromSystem(char c); static PIChar fromSystem(char c);
//! \~english Returns symbol from UTF8 codepage
//! \~russian Возвращает символ из UTF8 кодировки
static PIChar fromUTF8(const char * c); static PIChar fromUTF8(const char * c);
private: private:
@@ -132,54 +180,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); 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);} 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);} 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);} 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);} 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);} 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);} 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);} 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);} 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);} 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);} inline bool operator <=(const char * v, const PIChar & c) {return (PIChar(v) <= c);}
//! Compare operator //! \relatesalso PIChar
inline bool operator ==(const int v, const PIChar & c) {return (PIChar(v) == c);} //! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator ==(const int v, const PIChar & c) {return (PIChar((ushort)v) == c);}
//! Compare operator //! \relatesalso PIChar
inline bool operator >(const int v, const PIChar & c) {return (PIChar(v) > c);} //! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >(const int v, const PIChar & c) {return (PIChar((ushort)v) > c);}
//! Compare operator //! \relatesalso PIChar
inline bool operator <(const int v, const PIChar & c) {return (PIChar(v) < c);} //! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <(const int v, const PIChar & c) {return (PIChar((ushort)v) < c);}
//! Compare operator //! \relatesalso PIChar
inline bool operator >=(const int v, const PIChar & c) {return (PIChar(v) >= c);} //! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator >=(const int v, const PIChar & c) {return (PIChar((ushort)v) >= c);}
//! Compare operator //! \relatesalso PIChar
inline bool operator <=(const int v, const PIChar & c) {return (PIChar(v) <= c);} //! \~english Compare operator
//! \~russian Оператор сравнения
inline bool operator <=(const int v, const PIChar & c) {return (PIChar((ushort)v) <= c);}
#endif // PICHAR_H #endif // PICHAR_H

View File

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

View File

@@ -1,5 +1,8 @@
/*! @file pichunkstream.h /*! \file pichunkstream.h
* @brief Binary markup serializator * \ingroup Core
* \~\brief
* \~english Binary markup de/serializator stream
* \~russian Бинарный поток для де/сериализации с разметкой
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -26,24 +29,35 @@
#include "pibytearray.h" #include "pibytearray.h"
//! \ingroup Core
//! \~\brief
//! \~english Class for binary de/serialization.
//! \~russian Класс для бинарной де/сериализации.
class PIP_EXPORT PIChunkStream class PIP_EXPORT PIChunkStream
{ {
public: public:
//! \~english
//! Version of data packing. Read-access %PIChunkStream automatic detect version, but write-access //! Version of data packing. Read-access %PIChunkStream automatic detect version, but write-access
//! %PIChunkStream by default write in new version, be careful! //! %PIChunkStream by default write in new version, be careful!
//! \~russian
//! Версия хранения данных. %PIChunkStream на чтение автоматически определяет версию, но для записи
//! использует по умолчанию новую, осторожно!
enum Version { enum Version {
Version_1 /*! First, old version */, Version_1 /*! \~english First, old version \~russian Первая, старая версия */,
Version_2 /*! Second, more optimized version */ = 2, 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);} 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);} 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(Version v): version_(v) {setSource(0);}
~PIChunkStream(); ~PIChunkStream();
@@ -61,48 +75,64 @@ public:
const T & data; 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);} 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;} 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. //! Extract %PIByteArray from "data" and set it current stream.
//! If "read_all" then call \a readAll() after extract. //! If "read_all" then call \a readAll() after extract.
//! Returns if has data to read. //! Returns if has data to read.
//! \~russian
//! Извлекает %PIByteArray из "data" и инициализирует им поток.
//! Если указан "read_all", то вызывает \a readAll() после инициализации.
//! Возвращает если ли данные для чтения.
bool extract(PIByteArray & data, bool read_all = false); bool extract(PIByteArray & data, bool read_all = false);
void setSource(const PIByteArray & data); void setSource(const PIByteArray & data);
void setSource(PIByteArray * data); void setSource(PIByteArray * data);
//! Returns internal buffer with written data //! \~english Returns internal buffer with written data
//! \~russian Возвращает внутренний буфер с записанными данными
PIByteArray data() const; 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;} bool atEnd() const {return data_->size_s() <= 1;}
//! Returns stream version //! \~english Returns stream version
//! \~russian Возвращает версию потока
Version version() const {return (Version)version_;} 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(); 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(); void readAll();
//! Returns last readed chunk ID //! \~english Returns last readed chunk ID
//! \~russian Возвращает ID последнего прочитанного чанка
int getID() {return last_id;} int getID() {return last_id;}
//! Returns value of last readed chunk //! \~english Returns value of last readed chunk
//! \~russian Возвращает значение последнего прочитанного чанка
template <typename T> template <typename T>
T getData() const {T ret; PIByteArray s(last_data); s >> ret; return ret;} 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> template <typename T>
void get(T & v) const {v = getData<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> template <typename T>
const PIChunkStream & get(int id, T & v) const { const PIChunkStream & get(int id, T & v) const {
CacheEntry pos = data_map.value(id); CacheEntry pos = data_map.value(id);
@@ -113,7 +143,8 @@ public:
return *this; 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> template <typename T>
PIChunkStream & set(int id, const T & v) { PIChunkStream & set(int id, const T & v) {
PIByteArray ba; PIByteArray ba;

View File

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

View File

@@ -1,5 +1,8 @@
/*! @file picli.h /*! \file picli.h
* @brief Command-Line parser * \ingroup Core
* \~\brief
* \~english Command-Line parser
* \~russian Парсер командной строки
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -23,46 +26,65 @@
#ifndef PICLI_H #ifndef PICLI_H
#define PICLI_H #define PICLI_H
#include "piobject.h" #include "pistringlist.h"
#include "piset.h"
class PIP_EXPORT PICLI: public PIObject //! \ingroup Core
//! \~\brief
//! \~english Command-Line parser.
//! \~russian Парсер командной строки.
class PIP_EXPORT PICLI
{ {
PIOBJECT_SUBCLASS(PICLI, PIObject)
public: public:
//! Constructor //! \~english Constructor
//! \~russian Конструктор
PICLI(int argc, char * argv[]); 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;} 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;} 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;} 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;} 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;} 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 rawArgument(int index) {parse(); return _args_raw[index];}
PIString mandatoryArgument(int index) {parse(); return _args_mand[index];} PIString mandatoryArgument(int index) {parse(); return _args_mand[index];}
PIString optionalArgument(int index) {parse(); return _args_opt[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 & rawArguments() {parse(); return _args_raw;}
const PIStringList & mandatoryArguments() {parse(); return _args_mand;} const PIStringList & mandatoryArguments() {parse(); return _args_mand;}
const PIStringList & optionalArguments() {parse(); return _args_opt;} 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();} 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;} 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 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 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();} PIString argumentFullKey(const PIString & name) {piForeach (Argument &i, _args) if (i.name == name) return i.full_key; return PIString();}
@@ -76,6 +98,11 @@ public:
void setMandatoryArgumentsCount(const int count) {_count_mand = count; needParse = true;} void setMandatoryArgumentsCount(const int count) {_count_mand = count; needParse = true;}
void setOptionalArgumentsCount(const int count) {_count_opt = count; needParse = true;} void setOptionalArgumentsCount(const int count) {_count_opt = count; needParse = true;}
bool debug() const {return debug_;}
void setDebug(bool debug) {debug_ = debug;}
PIConstChars className() const {return "PICLI";}
PIString name() const {return PIStringAscii("CLI");}
private: private:
struct Argument { struct Argument {
Argument() {has_value = found = false;} Argument() {has_value = found = false;}
@@ -94,7 +121,7 @@ private:
PISet<PIString> keys_full, keys_short; PISet<PIString> keys_full, keys_short;
PIVector<Argument> _args; PIVector<Argument> _args;
int _count_mand, _count_opt; int _count_mand, _count_opt;
bool needParse; bool needParse, debug_;
}; };

View File

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

View File

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

View File

@@ -0,0 +1,164 @@
/*
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"
//! \~\class PIConstChars piconstchars.h
//! \~\details
//! \~english \section PIConstChars_sec0 Synopsis
//! \~russian \section PIConstChars_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::startsWith(const char c) const {
if (size() < 1) return false;
return str[0] == c;
}
bool PIConstChars::endsWith(const PIConstChars & str) const {
if (size() < str.size()) return false;
return str == right(str.size());
}
bool PIConstChars::endsWith(const char c) const {
if (size() < 1) return false;
return str[len - 1] == c;
}
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,262 @@
/*! \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"
//! \ingroup Core
//! \~\brief
//! \~english C-String class.
//! \~russian Класс C-строки.
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 starts with "c".
//! \~russian Возвращает начинается ли строка с "c".
bool startsWith(const char c) const;
//! \~english Returns if string ends with "str".
//! \~russian Возвращает оканчивается ли строка на "str".
bool endsWith(const PIConstChars & str) const;
//! \~english Returns if string ends with "c".
//! \~russian Возвращает оканчивается ли строка "c".
bool endsWith(const char c) 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 You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
//! \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 #ifndef PICOREMODULE_H
#define PICOREMODULE_H #define PICOREMODULE_H

View File

@@ -22,13 +22,88 @@
#include "pistack.h" #include "pistack.h"
#include "piobject.h" #include "piobject.h"
#include "pistring_std.h" #include "pistring_std.h"
#ifdef HAS_LOCALE
# include <locale>
# include <codecvt>
#endif
#ifdef WINDOWS #ifdef WINDOWS
# include <windows.h> # include <windows.h>
# include <wingdi.h>
# include <wincon.h> # include <wincon.h>
# define COMMON_LVB_UNDERSCORE 0x8000 # define COMMON_LVB_UNDERSCORE 0x8000
#endif #endif
//! \~\class PICout picout.h
//! \~\details
//! \~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 { class NotifierObject: public PIObject {
PIOBJECT(NotifierObject) PIOBJECT(NotifierObject)
public: public:
@@ -78,15 +153,12 @@ WORD PICout::__Private__::dattr = 0;
DWORD PICout::__Private__::smode = 0; DWORD PICout::__Private__::smode = 0;
#endif #endif
PICout::PICout(PIFlags<PICoutControl> controls): fo_(true), cc_(false), fc_(false), act_(true), cnb_(10), co_(controls) { PICout::PICout(int 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) {
init(); init();
} }
PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) { PICout::PICout(bool active): fo_(true), cc_(false), fc_(false), act_(active), cnb_(10), co_(PICoutManipulators::DefaultControls) {
buffer_ = nullptr;
if (act_) if (act_)
init(); init();
} }
@@ -203,54 +275,96 @@ PICout PICout::operator <<(const PICoutAction v) {
} }
#define PICOUTTOTARGET(v) { \ PICout PICout::operator <<(const PICoutManipulators::PICoutFormat v) {
if (buffer_) {\ switch (v) {
(*buffer_) << (v);\ case PICoutManipulators::Bin: cnb_ = 2; break;
} else {\ case PICoutManipulators::Oct: cnb_ = 8; break;
if (PICout::isOutputDeviceActive(PICout::StdOut)) std::cout << (v);\ case PICoutManipulators::Dec: cnb_ = 10; break;
if (PICout::isOutputDeviceActive(PICout::Buffer)) PICout::__string__() << (v);\ 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 write(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 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 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 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 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") write(PIString::fromNumber(ullong(v), 16)); return *this;}
PICout PICout::operator <<(const PIObject * v) { PICout PICout::operator <<(const PIObject * v) {
if (!act_) return *this; if (!act_) return *this;
@@ -259,9 +373,9 @@ PICout PICout::operator <<(const PIObject * v) {
else { else {
PICOUTTOTARGET(v->className()) PICOUTTOTARGET(v->className())
PICOUTTOTARGET("*(0x") PICOUTTOTARGET("*(0x")
PICOUTTOTARGETS(PIString::fromNumber(ullong(v), 16)) write(PIString::fromNumber(ullong(v), 16));
PICOUTTOTARGET(", \"") PICOUTTOTARGET(", \"")
PICOUTTOTARGET(v->name()) write(v->name());
PICOUTTOTARGET("\")") PICOUTTOTARGET("\")")
} }
return *this; return *this;
@@ -272,10 +386,10 @@ PICout PICout::operator <<(const PICoutSpecialChar v) {
switch (v) { switch (v) {
case Null: case Null:
if (buffer_) { if (buffer_) {
(*buffer_) << PIChar(0); (*buffer_) << PIChar();
} else { } else {
if (isOutputDeviceActive(StdOut)) std::cout << char(0); if (isOutputDeviceActive(StdOut)) std::cout << char(0);
if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar(0); if (isOutputDeviceActive(Buffer)) PICout::__string__() << PIChar();
} }
break; break;
case NewLine: case NewLine:
@@ -345,6 +459,12 @@ PICout & PICout::restoreControl() {
#undef PICOUTTOTARGET #undef PICOUTTOTARGET
#undef PINUMERICCOUT #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() { PICout & PICout::space() {
if (!act_) return *this; if (!act_) return *this;
if (!fo_ && co_[AddSpaces]) { if (!fo_ && co_[AddSpaces]) {
@@ -359,6 +479,12 @@ PICout & PICout::space() {
return *this; 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() { PICout & PICout::quote() {
if (!act_) return *this; if (!act_) return *this;
if (co_[AddQuotes]) { if (co_[AddQuotes]) {
@@ -373,6 +499,12 @@ PICout & PICout::quote() {
return *this; 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() { PICout & PICout::newLine() {
if (!act_) return *this; if (!act_) return *this;
if (co_[AddNewLine]) { if (co_[AddNewLine]) {
@@ -388,6 +520,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::write(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() { void PICout::init() {
#ifdef WINDOWS #ifdef WINDOWS
if (__Private__::hOut == 0) { if (__Private__::hOut == 0) {
@@ -398,7 +571,7 @@ void PICout::init() {
} }
attr_ = __Private__::dattr; attr_ = __Private__::dattr;
#endif #endif
buffer_ = 0; buffer_ = nullptr;
id_ = 0; id_ = 0;
if ((co_ & NoLock) != NoLock) if ((co_ & NoLock) != NoLock)
PICout::__mutex__().lock(); PICout::__mutex__().lock();

View File

@@ -1,5 +1,8 @@
/*! @file picout.h /*! \file picout.h
* @brief Universal output to console class * \ingroup Core
* \~\brief
* \~english Universal output to console class
* \~russian Универсальный вывод в консоль
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -27,10 +30,13 @@
#ifdef DOXYGEN #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 # 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 # define piCoutObj
#else #else
@@ -42,106 +48,100 @@
class PIObject; class PIObject;
//! @brief Namespace contains enums controlled PICout //! \relatesalso PICout
//! \~english Namespace contains enums that controls PICout
//! \~russian Пространство имен содержит перечисления для контроля PICout
namespace PICoutManipulators { namespace PICoutManipulators {
//! @brief Enum contains special characters //! \~english Enum contains special characters
//! \~russian Перечисление со спецсимволами
enum PICoutSpecialChar { enum PICoutSpecialChar {
Null /*! Null-character, '\\0' */, Null /*! \~english Null-character, '\\0' \~russian Нулевой символ, '\\0' */,
NewLine /*! New line character, '\\n' */, NewLine /*! \~english New line character, '\\n' \~russian Новая строка, '\\n' */,
Tab /*! Tab character, '\\t' */, Tab /*! \~english Tab character, '\\t' \~russian Табуляция, '\\t' */,
Esc /*! Escape character, '\\e' */, Esc /*! \~english Escape character, '\\e' \~russian Esc-символ, '\\e' */,
Quote /*! Quote character, '"' */ Quote /*! \~english Quote character, '\"' \~russian Кавычки, '\"' */
}; };
//! @brief Enum contains immediate action //! \~english Enum contains immediate action
//! \~russian Перечисление с немедленными действиями
enum PICoutAction { enum PICoutAction {
Flush /*! Flush the output */, Flush /*! \~english Flush the output \~russian Обновить вывод */,
Backspace /*! Remove last symbol */, Backspace /*! \~english Remove last symbol \~russian Удалить последний символ */,
ShowCursor /*! Show cursor */, ShowCursor /*! \~english Show cursor \~russian Показать курсор */,
HideCursor /*! Hide cursor */, HideCursor /*! \~english Hide cursor \~russian Скрыть курсор */,
ClearLine /*! Clear current line */, ClearLine /*! \~english Clear current line \~russian Очистить текущую строку */,
ClearScreen /*! Clear the screen */, ClearScreen /*! \~english Clear the screen \~russian Очистить экран */,
SaveContol /*! Save control flags, equivalent to \a saveControl() */, SaveContol /*! \~english Save control flags, equivalent to \a saveControl() \~russian Сохранить флаги, аналогично \a saveControl() */,
RestoreControl /*! Restore control flags, equivalent to \a restoreControl() */ 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 { enum PICoutControl {
AddNone /*! No controls */ = 0x0, AddNone /*! \~english No controls \~russian Без управления */ = 0x0,
AddSpaces /*! Spaces will be appear after each output */ = 0x1, AddSpaces /*! \~english Spaces will be appear after each output \~russian Пробел после каждого вывода */ = 0x1,
AddNewLine /*! New line will be appear after all output */ = 0x2, AddNewLine /*! \~english New line will be appear after all output \~russian Новая строка после завершения вывода */ = 0x2,
AddQuotes /*! Each string will be quoted */ = 0x4, AddQuotes /*! \~english Each string will be quoted \~russian Каждая строка в кавычках */ = 0x4,
DefaultControls /*! Default controls */ = AddSpaces | AddNewLine, DefaultControls /*! \~english Default controls \~russian Управление по умолчанию */ = AddSpaces | AddNewLine,
AddAll /*! All controls */ = 0xFF, AddAll /*! \~english All controls \~russian Всё управление */ = 0xFF,
NoLock /*! Don`t use mutex for output */ = 0x100, NoLock /*! \~english Don`t use mutex for output \~russian Не использовать мьютекс при выводе */ = 0x100,
}; };
//! @brief Enum contains output format //! \~english Enum contains output format
//! \~russian Перечисление с форматом вывода
enum PICoutFormat { enum PICoutFormat {
Bin /*! Binary representation of integers */ = 0x01, Bin /*! \~english Binary representation of integers \~russian Двоичное представление для целых чисел */ = 0x01,
Oct /*! Octal representation of integers */ = 0x02, Oct /*! \~english Octal representation of integers \~russian Восьмеричное представление для целых чисел */ = 0x02,
Dec /*! Decimal representation of integers */ = 0x04, Dec /*! \~english Decimal representation of integers \~russian Десятичное представление для целых чисел */ = 0x04,
Hex /*! Hexadecimal representation of integers */ = 0x08, Hex /*! \~english Hexadecimal representation of integers \~russian Шестнадцатеричное представление для целых чисел */ = 0x08,
Bold /*! Bold */ = 0x10, Bold /*! \~english Bold \~russian Жирный */ = 0x10,
Faint /*! */ = 0x20, Faint /*! \~english \~russian */ = 0x20,
Italic /*! */ = 0x40, Italic /*! \~english \~russian */ = 0x40,
Underline /*! Underline */ = 0x80, Underline /*! \~english Underline \~russian Подчеркнутый */ = 0x80,
Blink /*! Blink */ = 0x100, Blink /*! \~english Blink \~russian Мигающий */ = 0x100,
Black /*! Black font */ = 0x400, Black /*! \~english Black font \~russian Чёрный */ = 0x400,
Red /*! Red font */ = 0x800, Red /*! \~english Red font \~russian Красный */ = 0x800,
Green /*! Green font */ = 0x1000, Green /*! \~english Green font \~russian Зелёный */ = 0x1000,
Blue /*! Blue font */ = 0x2000, Blue /*! \~english Blue font \~russian Синий */ = 0x2000,
Yellow /*! Yellow font */ = 0x4000, Yellow /*! \~english Yellow font \~russian Жёлтый */ = 0x4000,
Magenta /*! Magenta font */ = 0x8000, Magenta /*! \~english Magenta font \~russian Пурпурный */ = 0x8000,
Cyan /*! Cyan font */ = 0x10000, Cyan /*! \~english Cyan font \~russian Голубой */ = 0x10000,
White /*! White font */ = 0x20000, White /*! \~english White font \~russian Белый */ = 0x20000,
BackBlack /*! Black background */ = 0x40000, BackBlack /*! \~english Black background \~russian Чёрный фон */ = 0x40000,
BackRed /*! Red background */ = 0x80000, BackRed /*! \~english Red background \~russian Красный фон */ = 0x80000,
BackGreen /*! Green background */ = 0x100000, BackGreen /*! \~english Green background \~russian Зелёный фон */ = 0x100000,
BackBlue /*! Blue background */ = 0x200000, BackBlue /*! \~english Blue background \~russian Синий фон */ = 0x200000,
BackYellow /*! Yellow background */ = 0x400000, BackYellow /*! \~english Yellow background \~russian Жёлтый фон */ = 0x400000,
BackMagenta /*! Magenta background */ = 0x800000, BackMagenta /*! \~english Magenta background \~russian Пурпурный фон */ = 0x800000,
BackCyan /*! Cyan background */ = 0x1000000, BackCyan /*! \~english Cyan background \~russian Голубой фон */ = 0x1000000,
BackWhite /*! White background */ = 0x2000000, BackWhite /*! \~english White background \~russian Белый фон */ = 0x2000000,
Default /*! Default format */ = 0x4000000 Default /*! \~english Default format \~russian Формат по умолчанию */ = 0x4000000
}; };
typedef PIFlags<PICoutControl> PICoutControls; 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
*/
//! \ingroup Core
//! \~\brief
//! \~english Universal output to console class.
//! \~russian Универсальный вывод в консоль.
class PIP_EXPORT PICout { class PIP_EXPORT PICout {
public: 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); 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(PIString * buffer, int id = 0, PIFlags<PICoutManipulators::PICoutControl> controls = PICoutManipulators::AddSpaces | PICoutManipulators::AddNewLine);
PICout(const PICout & other); PICout(const PICout & other);
@@ -149,171 +149,187 @@ public:
~PICout(); ~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 { class PIP_EXPORT Notifier {
public: public:
//! \~english Singleton access to %PICout::Notifier
//! \~russian Синглтон класса %PICout::Notifier
static Notifier * instance(); static Notifier * instance();
//! \~english Object that emit events from %PICout
//! \~russian Объект, который посылает события от %PICout
static PIObject * object(); static PIObject * object();
private: private:
Notifier(); Notifier();
PIObject * o; PIObject * o;
}; };
//! @brief Enum contains output devices of PICout //! \~english Enum contains output devices of %PICout
//! \~russian Перечисление с устройствами вывода для %PICout
enum OutputDevice { enum OutputDevice {
NoDevices /** PICout is disabled */ = 0x0, NoDevices /** \~english %PICout is disabled \~russian %PICout неактивен */ = 0x0,
StdOut /** Standard console output */ = 0x1, StdOut /** \~english Standard console output \~russian Стандартный вывод в консоль */ = 0x1,
Buffer /** Internal buffer */ = 0x2, Buffer /** \~english Internal buffer \~russian Внутренний буфер */ = 0x2,
AllDevices /** All */ = 0xFFFF, AllDevices /** \~english All \~russian Все */ = 0xFFFF,
}; };
typedef PIFlags<OutputDevice> OutputDevices; 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); 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); //PICout operator <<(const std::string & v);
//! Output operator for boolean values //! \~english Output operator for boolean values
//! \~russian Оператор вывода для логических значений
PICout operator <<(const bool v); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); PICout operator <<(const double v);
//! Output operator for pointers //! \~english Output operator for pointers
//! \~russian Оператор вывода для указателей
PICout operator <<(const void * v); 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); 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); PICout operator <<(const PICoutManipulators::PICoutSpecialChar v);
//! Output operator for \a PIFlags<PICoutFormat> values //! \~english Output operator for \a PIFlags<PICoutFormat> values
PICout operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v) { //! \~russian Оператор вывода для \a PIFlags<PICoutFormat>
if (v[PICoutManipulators::Bin]) cnb_ = 2; PICout operator <<(const PIFlags<PICoutManipulators::PICoutFormat> & v);
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;
}
//! Output operator for \a PICoutFormat values //! \~english Output operator for \a PICoutFormat values
PICout operator <<(const PICoutManipulators::PICoutFormat v) { //! \~russian Оператор вывода для \a PICoutFormat
switch (v) { PICout operator <<(const PICoutManipulators::PICoutFormat 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;
}
//! Do some action //! \~english Do some action
//! \~russian Делает действие
PICout operator <<(const PICoutManipulators::PICoutAction v); 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;} 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;} 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(); PICout & saveControl();
//! Restore control flags from internal stack \sa \a saveControl() //! \~english Restore control flags from internal stack
//! \~russian Восстанавливает состояние флагов из внутреннего стека
//! \~\sa \a saveControl()
PICout & restoreControl(); PICout & restoreControl();
/*! @brief Conditional put space character to output //! \~english Conditional put space character to output
* \details If it is not a first output and control \a AddSpaces is set //! \~russian Условно добавляет пробел
* space character is put \sa \a quote(), \a newLine() */
PICout & space(); PICout & space();
/*! @brief Conditional put quote character to output //! \~english Conditional put quote character to output
* \details If control \a AddQuotes is set //! \~russian Условно добавляет кавычки
* quote character is put \sa \a space(), \a newLine() */
PICout & quote(); PICout & quote();
/*! @brief Conditional put new line character to output //! \~english Conditional put new line character to output
* \details If control \a AddNewLine is set //! \~russian Условно добавляет новую строку
* new line character is put \sa \a space(), \a quote() */
PICout & newLine(); 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 & write(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); static bool setBufferActive(bool on, bool clear = false);
//! \~english Equivalent to \a isOutputDeviceActive(OutputDevice)
//! \~russian Аналог \a isOutputDeviceActive(OutputDevice)
static bool isBufferActive(); static bool isBufferActive();
//! \~english Returns internal PIString buffer and if "clear" clear it
//! \~russian Возвращает внутренний PIString буфер и если "clear" то очищает его
static PIString buffer(bool clear = false); static PIString buffer(bool clear = false);
//! \~english Clear internal PIString buffer
//! \~russian Очищает внутренний PIString буфер
static void clearBuffer(); 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); static bool setOutputDevice(OutputDevice d, bool on = true);
//! \~english Set output to devices to "d"
//! \~russian Устанавливает устройства вывода "d"
static void setOutputDevices(OutputDevices d); static void setOutputDevices(OutputDevices d);
//! \~english Returns if output device "d" is active
//! \~russian Возвращает активно ли устройство вывода "d"
static bool isOutputDeviceActive(OutputDevice d); static bool isOutputDeviceActive(OutputDevice d);
static PIMutex & __mutex__(); static PIMutex & __mutex__();

View File

@@ -0,0 +1,350 @@
/*
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
//!
//! \~\class PIDate pidatetime.h
//!
//! \~\class PIDateTime pidatetime.h
//!
//! \}
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;
}

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

@@ -0,0 +1,330 @@
/*! \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"
//! \ingroup Core
//! \~\brief
//! \~english Calendar time.
//! \~russian Календарное время.
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);
//! \ingroup Core
//! \~\brief
//! \~english Calendar date.
//! \~russian Календарная дата.
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);
//! \ingroup Core
//! \~\brief
//! \~english Calendar date and time.
//! \~russian Календарное дата и время.
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 /*! \file piflags.h
* @brief General flags class * \ingroup Core
* \~\brief
* \~english General flags class
* \~russian Универсальные флаги
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -25,109 +28,220 @@
#include "pip_export.h" #include "pip_export.h"
/*! @brief This class used as container for bit flags //! \addtogroup Core
* \details PIFlags is wrapper around \c "int". There are many //! \{
* bit-wise operators, native conversion to int and function //! \~\class PIFlags piflags.h
* to test flag. \n Example: //! \~\brief
* \snippet piincludes.cpp flags //! \~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> template<typename Enum>
class PIFlags { class PIFlags {
public: public:
//! Constructor with flags = 0
//! \~english Constructor with flags = 0
//! \~russian Создает нулевые флаги
PIFlags(): flags(0) {;} PIFlags(): flags(0) {;}
//! Constructor with flags = Enum "e"
//! \~english Constructor with flags = Enum "e"
//! \~russian Создает флаги со значением = Enum "e"
PIFlags(Enum e): flags(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) {;} 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;} 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;} 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;} 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;} void operator =(const Enum & e) {flags = e;}
//! copy operator
//! \~english Assign operator
//! \~russian Оператор присваивания
void operator =(const int & i) {flags = i;} void operator =(const int & i) {flags = i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const PIFlags & f) {return flags == f.flags;} bool operator ==(const PIFlags & f) {return flags == f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const Enum & e) {return flags == e;} bool operator ==(const Enum & e) {return flags == e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator ==(const int i) {return flags == i;} bool operator ==(const int i) {return flags == i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const PIFlags & f) {return flags != f.flags;} bool operator !=(const PIFlags & f) {return flags != f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const Enum & e) {return flags != e;} bool operator !=(const Enum & e) {return flags != e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator !=(const int i) {return flags != i;} bool operator !=(const int i) {return flags != i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const PIFlags & f) {return flags > f.flags;} bool operator >(const PIFlags & f) {return flags > f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const Enum & e) {return flags > e;} bool operator >(const Enum & e) {return flags > e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >(const int i) {return flags > i;} bool operator >(const int i) {return flags > i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const PIFlags & f) {return flags < f.flags;} bool operator <(const PIFlags & f) {return flags < f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const Enum & e) {return flags < e;} bool operator <(const Enum & e) {return flags < e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <(const int i) {return flags < i;} bool operator <(const int i) {return flags < i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const PIFlags & f) {return flags >= f.flags;} bool operator >=(const PIFlags & f) {return flags >= f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const Enum & e) {return flags >= e;} bool operator >=(const Enum & e) {return flags >= e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator >=(const int i) {return flags >= i;} bool operator >=(const int i) {return flags >= i;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const PIFlags & f) {return flags <= f.flags;} bool operator <=(const PIFlags & f) {return flags <= f.flags;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const Enum & e) {return flags <= e;} bool operator <=(const Enum & e) {return flags <= e;}
//! compare operator
//! \~english Compare operator
//! \~russian Оператор сравнения
bool operator <=(const int i) {return flags <= i;} 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;} 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;} void operator &=(const Enum & e) {flags &= e;}
//! Bit-wise AND operator
//! \~english Bit-wise AND operator
//! \~russian Оператор побитового И
void operator &=(const int i) {flags &= i;} 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;} 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;} void operator |=(const Enum & e) {flags |= e;}
//! Bit-wise OR operator
//! \~english Bit-wise OR operator
//! \~russian Оператор побитового ИЛИ
void operator |=(const int i) {flags |= i;} 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;} 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;} void operator ^=(const Enum & e) {flags ^= e;}
//! Bit-wise XOR operator
//! \~english Bit-wise XOR operator
//! \~russian Оператор побитового исключающего ИЛИ
void operator ^=(const int i) {flags ^= i;} 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;} 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;} 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;} 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;} 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;} 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;} 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;} 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;} 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;} 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;} 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;} operator int() const {return flags;}
private: private:
int flags; int flags;
}; };
#endif // PIFLAGS_H #endif // PIFLAGS_H

View File

@@ -64,10 +64,16 @@ void errorClear() {
PIString errorString() { PIString errorString() {
#ifdef WINDOWS #ifdef WINDOWS
char * msg; char * msg = nullptr;
int err = GetLastError(); 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); 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 #else
int e = errno; int e = errno;
return PIString("code ") + PIString::fromNumber(e) + " - " + PIString(strerror(e)); 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() { void randomize() {
srand(PISystemTime::current(true).nanoseconds); srand(PISystemTime::current(true).nanoseconds);
} }
@@ -93,154 +94,3 @@ void randomize() {
int randomi() { int randomi() {
return rand(); return rand();
} }
/*! \mainpage What is PIP
* 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++.
* Library contains many classes, some of them are pure abstract, some classes
* can be used as they are, some classes should be inherited to new classes.
* PIP provide classes:
* * direct output to console (\a PICout)
* * containers (\a PIVector, \a PIList, \a PIMap, \a PIStack)
* * byte array (\a PIByteArray)
* * string (\a PIString, \a PIStringList)
* * base object (events and handlers) (\a PIObject)
* * multithreading
* * thread (\a PIThread)
* * executor (\a PIThreadPoolExecutor)
* * blocking dequeue (\a PIBlockingDequeue)
* * timer (\a PITimer)
* * console (information output) (\a PIConsole)
* * stand-alone
* * server
* * client
* * I/O devices
* * base class (\a PIIODevice)
* * file (\a PIFile)
* * serial port (\a PISerial)
* * ethernet (\a PIEthernet)
* * USB (\a PIUSB)
* * packets extractor (\a PIPacketExtractor)
* * binary log (\a PIBinaryLog)
* * complex I/O point (\a PIConnection)
* * Run-time libraries
* * abstract (\a PILibrary)
* * plugin (\a PIPluginLoader)
* * connection quality diagnotic (\a PIDiagnostics)
* * command-line arguments parser (\a PICLI)
* * math evaluator (\a PIEvaluator)
* * peering net node (\a PIPeer)
* * process (\a PIProcess)
* * state machine (\a PIStateMachine)
* \n \n Basic using of PIP described at page \ref using_basic */
/*! \page using_basic Getting started
* 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
\code{.cpp}
#include <pip.h>
// declare key press handler
void key_event(char key, void * );
PIConsole console(false, key_event); // don`t start now, key handler is "key_event"
// some vars
int i = 2, j = 3;
// implicit key press handler
void key_event(char key, void * ) {
switch (key) {
case '-':
i--;
break;
case '+':
i++;
break;
case '(':
j--;
break;
case ')':
j++;
break;
};
};
class MainClass: public PITimer {
PIOBJECT(MainClass)
public:
MainClass() {}
protected:
void tick(void * data, int delimiter) {
piCout << "timer tick";
// timer tick
}
};
MainClass main_class;
int main(int argc, char * argv[]) {
// enabling auto-detection of exit button press, by default 'Q' (shift+q)
console.enableExitCapture();
// if we want to parse command-line arguments
PICLI cli(argc, argv);
cli.addArgument("console"); // "-c" or "--console"
cli.addArgument("debug"); // "-d" or "--debug"
// enabling or disabling global debug flag
piDebug = cli.hasArgument("debug");
// configure console
console.addTab("first tab", '1');
console.addString("PIP console", 1, PIConsole::Bold);
console.addVariable("int var (i)", &i, 1);
console.addVariable("int green var (j)", &j, 1, PIConsole::Green);
console.addString("'-' - i--", 2);
console.addString("'+' - i++", 2);
console.addString("'(' - j--", 2);
console.addString("')' - j++", 2);
console.addTab("second tab", '2');
console.addString("col 1", 1);
console.addString("col 2", 2);
console.addString("col 3", 3);
console.setTab("first tab");
// start output to console if "console" argument exists
if (cli.hasArgument("console"))
console.start();
// start main class, e.g. 40 Hz
main_class.start(25.);
// wait for 'Q' press, independently if console is started or not
console.waitForFinish();
return 0;
};
\endcode
* 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 */
/*! \page using_advanced Advanced using
* Sorry, creativity crysis xD
*/

View File

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

View File

@@ -40,6 +40,15 @@ typedef LONG(NTAPI*PINtSetTimerResolution)(ULONG, BOOLEAN, PULONG);
#include <cstdio> #include <cstdio>
#include <iostream> #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 #endif // PIINCLUDES_P_H

View File

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

View File

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

View File

@@ -18,62 +18,162 @@
*/ */
#include "piobject.h" #include "piobject.h"
#include "pisysteminfo.h"
#include "pithread.h" #include "pithread.h"
#include "piconditionvar.h" #include "piconditionvar.h"
#ifndef FREERTOS #ifndef MICRO_PIP
# include "pisysteminfo.h"
# include "pifile.h" # include "pifile.h"
#endif #endif
/** \class PIObject
* @brief This is base class for any classes which use events -> handlers mechanism. //! \~\class PIObject piobject.h
* \details //! \~\details
* \section PIObject_sec0 Events and Event handlers //! \~english \section PIObject_sec0 Events and Event handlers
* %PIObject provide notification mechanism similar Qt but implemented //! \~russian \section PIObject_sec0 События и Обработчики событий
* on language capabilities without any special preprocessors or compilers. //!
* Any class inherits PIObject should use macro \a PIOBJECT() immediate //! \~english
* after declaration to proper compile. //! %PIObject provide notification mechanism similar Qt but implemented
* //! on language capabilities without any special preprocessors or compilers.
* Event is a some abstract event that can be raised at any time. //! Any class inherits %PIObject should use macro \a PIOBJECT() immediate
* Event is a function but declared with special macro \a EVENT(). //! after declaration to proper compile.
* To raise event simply execute event function. //!
* //! Event is a some abstract event that can be raised at any time as common method.
* Event handler is a function but declared with special macro //! Event is a function but declared with special macro \a EVENT() and don`t need definition.
* \a EVENT_HANDLER(). You can use event handlers as ordinary functions. //! To raise event simply execute event function.
* //!
* Main goal of this mechanism is perform abstract connections between //! Event handler is a function but declared with special macro
* various objects. This functionality provide macro \a CONNECT() which //! \a EVENT_HANDLER(). It need definition as common method.
* connect some event of first object to some event handler or event of //! You can use event handlers as ordinary functions.
* second object. Each event can be connected any times to any event handlers. //!
* //! Main goal of this mechanism is perform abstract connections between
* \image html events_handlers.png //! 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
* Example: \snippet piobject.cpp main //! second object. Each event can be connected any times to any event handlers.
* Result: //!
\code{.cpp} //! * \a CONNECT() macros family work with explicit subclasses of %PIObject with compile-time check of events and handlers
handler B: 2 , 0.5 //! * \a CONNECTU() macro can work implicit subclasses of %PIObject with run-time check of events and handlers
handler A: event to handler //! * \a CONNECTU_QUEUED() macro similar to \a CONNECTU() macro but queue execution with performer object instead of handler direct call
handler A: event to event //! * \a CONNECTL() macro work with implicit subclasses of %PIObject and lambda-function
\endcode //!
*/ //! \~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
//!
//! \~\class PIObject::Connection piobject.h
//! \~\details
//!
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 { 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 PIObject::__MetaFunc::fullFormat() const {
PIString ret = type_ret + " " + scope + "::" + func_name +"("; PIString ret = PIStringAscii(type_ret) + " " +
for (int i = 0; i < types.size_s(); ++i) { PIStringAscii(scope) + "::" +
PIStringAscii(func_name) +"(";
for (int i = 0; i < __PIOBJECT_MAX_ARGS__; ++i) {
if (!types[i]) break;
if (i > 0) ret += ", "; if (i > 0) ret += ", ";
ret += types[i] + " " + names[i]; ret += PIStringAscii(types[i]) + " " + PIStringAscii(names[i]);
} }
ret += ")"; ret += ")";
return 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) { PIObject::PIObject(const PIString & name): _signature_(__PIOBJECT_SIGNATURE__), emitter_(0), thread_safe_(false), proc_event_queue(false) {
in_event_cnt = 0; in_event_cnt = 0;
setName(name); setName(name);
@@ -91,17 +191,10 @@ PIObject::~PIObject() {
mutexObjects().lock(); mutexObjects().lock();
objects().removeAll(this); objects().removeAll(this);
mutexObjects().unlock(); 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 +234,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 PIObject::scopeList() const {
PIStringList ret;
ret.reserve(2);
PIMutexLocker ml(__meta_mutex()); 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 +256,11 @@ PIStringList PIObject::methodsEH() const {
bool PIObject::isMethodEHContains(const PIString & name) const { bool PIObject::isMethodEHContains(const PIString & name) const {
uint search_id = name.hash();
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
const __MetaData & ehd(__meta_data()[classNameID()]); const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) { 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 true;
} }
return false; return false;
@@ -213,10 +268,11 @@ bool PIObject::isMethodEHContains(const PIString & name) const {
PIString PIObject::methodEHArguments(const PIString & name) const { PIString PIObject::methodEHArguments(const PIString & name) const {
uint search_id = name.hash();
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
const __MetaData & ehd(__meta_data()[classNameID()]); const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) { 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 eh.value().arguments();
} }
return PIString(); return PIString();
@@ -224,10 +280,11 @@ PIString PIObject::methodEHArguments(const PIString & name) const {
PIString PIObject::methodEHFullFormat(const PIString & name) const { PIString PIObject::methodEHFullFormat(const PIString & name) const {
uint search_id = name.hash();
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
const __MetaData & ehd(__meta_data()[classNameID()]); const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) { 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 eh.value().fullFormat();
} }
return PIString(); return PIString();
@@ -240,10 +297,11 @@ PIString PIObject::methodEHFromAddr(const void * addr) const {
PIVector<PIObject::__MetaFunc> PIObject::findEH(const PIString & name) const { PIVector<PIObject::__MetaFunc> PIObject::findEH(const PIString & name) const {
uint search_id = name.hash();
PIVector<__MetaFunc> ret; PIVector<__MetaFunc> ret;
const __MetaData & ehd(__meta_data()[classNameID()]); const __MetaData & ehd(__meta_data()[classNameID()]);
for (auto eh = ehd.eh_func.constBegin(); eh != ehd.eh_func.constEnd(); eh++) { 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(); ret << eh.value();
} }
return ret; return ret;
@@ -256,31 +314,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 ...";
//piCout << "piConnect" << src << (void*)(dest) << sig; //piCout << "piConnect" << src << (void*)(dest) << sig;
//piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className(); //piCout << "piConnect" << src->className() << "->" << ((PIObject*)dest)->className();
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest_o->mutex_connect, src != dest_o); 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 << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s() << "...";
//piCout << "addConnector" << dest_o << src; //piCout << "addConnector" << dest_o << src;
dest_o->connectors << src; dest_o->connectors << src;
//piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s(); //piCout << "piConnect" << ((PIObject*)dest) << sig << ((PIObject*)dest)->connectors.size_s();
//piCout << "piConnect ok"; //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) { 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 false; if (src == 0 || dest_o == 0 || dest == 0) return Connection();
if (!src->isPIObject()) { if (!src->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")"; piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: source object is not PIObject! (" << loc << ")";
return false; return Connection();
} }
if (!dest_o->isPIObject()) { if (!dest_o->isPIObject()) {
piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")"; piCout << "[piConnectU] \"" << sig << "\" -> \"" << hname << "\" error: destination object is not PIObject! (" << loc << ")";
return false; return Connection();
} }
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect); PIMutexLocker mls(src->mutex_connect);
@@ -288,11 +348,11 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_
PIVector<__MetaFunc> m_src = src->findEH(sig), m_dest = dest_o->findEH(hname); PIVector<__MetaFunc> m_src = src->findEH(sig), m_dest = dest_o->findEH(hname);
if (m_src.isEmpty()) { if (m_src.isEmpty()) {
piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")"; piCout << "[piConnectU] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
return false; return Connection();
} }
if (m_dest.isEmpty()) { if (m_dest.isEmpty()) {
piCout << "[piConnectU] Error: can`t find handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")"; 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); void * addr_src(0), * addr_dest(0);
int args(0); int args(0);
@@ -301,35 +361,35 @@ bool PIObject::piConnectU(PIObject * src, const PIString & sig, PIObject * dest_
if (addr_src != 0) break; if (addr_src != 0) break;
piForeachC (__MetaFunc & fd, m_dest) { piForeachC (__MetaFunc & fd, m_dest) {
if (addr_src != 0) break; if (addr_src != 0) break;
if (fs.arguments().startsWith(fd.arguments()) || fd.arguments().isEmpty()) { if (fs.canConnectTo(fd, args)) {
addr_src = fs.addr; addr_src = fs.addr;
addr_dest = que ? fd.addrV : fd.addr; addr_dest = que ? fd.addrV : fd.addr;
args = fd.names.size_s();
} }
} }
} }
if (addr_src == 0) { if (addr_src == 0) {
piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className() piCout << "[piConnectU] Error: can`t find suitable pair of event \"" << sig << "\" in class \"" << src->className()
<< "\" and handler \"" << hname << "\" in class \"" << dest_o->className() << "\"! (" << loc << ")"; << "\" 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; if (que) performer->proc_event_queue = true;
dest_o->connectors << src; dest_o->connectors << src;
//piCout << cc << cq << _ol.size();//"connect" << src << "->" << dest_o << ", dest.connectors.size() =" << dest_o->connectors.size(); //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) { if (src == 0) {
delete f; delete f;
return false; return Connection();
} }
if (!src->isPIObject()) { if (!src->isPIObject()) {
piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")"; piCout << "[piConnectLS] \"" << sig << "\" -> [lambda] error: source object is not PIObject! (" << loc << ")";
delete f; delete f;
return false; return Connection();
} }
PIMutexLocker ml(__meta_mutex()); PIMutexLocker ml(__meta_mutex());
PIMutexLocker mls(src->mutex_connect); PIMutexLocker mls(src->mutex_connect);
@@ -338,19 +398,19 @@ bool PIObject::piConnectLS(PIObject * src, const PIString & sig, std::function<v
if (m_src.isEmpty()) { if (m_src.isEmpty()) {
piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")"; piCout << "[piConnectLS] Error: can`t find event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f; delete f;
return false; return Connection();
} }
if (m_src.size() != 1) { if (m_src.size() != 1) {
piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")"; piCout << "[piConnectLS] Error: can`t connect overloaded event \"" << sig << "\" in class \"" << src->className() << "\"! (" << loc << ")";
delete f; 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"; //piCout << "found";
conn.functor = f; conn.functor = f;
src->connections << conn; src->connections << conn;
//piCout << "finished"; //piCout << "finished";
return true; return conn;
} }
@@ -358,7 +418,7 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest); PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) { 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) { if (cc.event == sig && cc.dest_o == dest && cc.slot == ev_h) {
src->connections[i].destroy(); src->connections[i].destroy();
src->connections.remove(i); src->connections.remove(i);
@@ -373,7 +433,7 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
PIMutexLocker _mld(dest->mutex_connect, src != dest); PIMutexLocker _mld(dest->mutex_connect, src != dest);
for (int i = 0; i < src->connections.size_s(); ++i) { 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) { if (cc.event == sig && cc.dest_o == dest) {
src->connections[i].destroy(); src->connections[i].destroy();
src->connections.remove(i); src->connections.remove(i);
@@ -387,14 +447,14 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig, PIObject * des
void PIObject::piDisconnect(PIObject * src, const PIString & sig) { void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
PIMutexLocker _ml(src->mutex_connect); PIMutexLocker _ml(src->mutex_connect);
for (int i = 0; i < src->connections.size_s(); ++i) { for (int i = 0; i < src->connections.size_s(); ++i) {
__Connection & cc(src->connections[i]); Connection & cc(src->connections[i]);
if (cc.event == sig) { if (cc.event == sig) {
PIObject * dest = cc.dest_o; PIObject * dest = cc.dest_o;
if (!dest) { src->connections[i].destroy();
src->connections[i].destroy(); src->connections.remove(i);
src->connections.remove(i); i--;
i--; if (dest) {
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS) #if !defined(ANDROID) && !defined(MAC_OS) && !defined(MICRO_PIP)
PIMutexLocker _mld(dest->mutex_connect, src != dest); PIMutexLocker _mld(dest->mutex_connect, src != dest);
#endif #endif
dest->updateConnectors(); dest->updateConnectors();
@@ -404,37 +464,38 @@ void PIObject::piDisconnect(PIObject * src, const PIString & sig) {
} }
void PIObject::piDisconnect(PIObject * src) { void PIObject::piDisconnectAll() {
src->deleted(src); PIMutexLocker _ml(mutex_connect);
PIMutexLocker _ml(src->mutex_connect); PIVector<PIObject * > cv = connectors.toVector();
PIVector<PIObject * > cv = src->connectors.toVector(); // piCout << "disconnect connectors =" << connectors.size();
piForeach (PIObject * o, cv) { piForeach (PIObject * o, cv) {
//piCout << "disconnect"<< src->className()<< o->className(); // piCout << "disconnect"<< src << o;
if (!o || (o == src)) continue; if (!o || (o == this)) continue;
if (!o->isPIObject()) continue; if (!o->isPIObject()) continue;
#if !defined(ANDROID) && !defined(MAC_OS) && !defined(FREERTOS) #if !defined(ANDROID) && !defined(MAC_OS) && !defined(MICRO_PIP)
PIMutexLocker _mld(o->mutex_connect, src != o); PIMutexLocker _mld(o->mutex_connect, this != o);
#endif #endif
PIVector<__Connection> & oc(o->connections); PIVector<Connection> & oc(o->connections);
for (int i = 0; i < oc.size_s(); ++i) { for (int i = 0; i < oc.size_s(); ++i) {
if (oc[i].functor) continue; if (oc[i].functor) continue;
//piCout << " check" << (void*)(oc[i].dest_o) << "==" << (void*)(src); //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[i].destroy();
oc.remove(i); oc.remove(i);
--i; --i;
} }
} }
} }
piForeachC (PIObject::__Connection & c, src->connections) { // piCout << "disconnect connections =" << connections.size();
piForeachC (PIObject::Connection & c, connections) {
if (c.functor) continue; if (c.functor) continue;
if (!c.dest_o) continue; if (!c.dest_o) continue;
if (!c.dest_o->isPIObject()) 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) for (int i = 0; i < connections.size_s(); ++i)
src->connections[i].destroy(); connections[i].destroy();
src->connections.clear(); connections.clear();
} }
@@ -444,8 +505,8 @@ void PIObject::updateConnectors() {
PIMutexLocker _ml(mutexObjects()); PIMutexLocker _ml(mutexObjects());
piForeach (PIObject * o, objects()) { piForeach (PIObject * o, objects()) {
if (o == this) continue; if (o == this) continue;
PIVector<__Connection> & oc(o->connections); PIVector<Connection> & oc(o->connections);
piForeach (__Connection & c, oc) piForeach (Connection & c, oc)
if (c.dest == this) if (c.dest == this)
connectors << o; connectors << o;
} }
@@ -492,6 +553,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() { void PIObject::deleteLater() {
Deleter::instance()->post(this); Deleter::instance()->post(this);
} }
@@ -506,7 +575,7 @@ bool PIObject::findSuitableMethodV(const PIString & method, int args, int & ret_
int mfi = -1, ac = -1, mac = -1; int mfi = -1, ac = -1, mac = -1;
for (int i = 0; i < ml.size_s(); ++i) { for (int i = 0; i < ml.size_s(); ++i) {
__MetaFunc & m(ml[i]); __MetaFunc & m(ml[i]);
int j = m.names.size_s(); int j = m.argumentsCount();
if (mac < 0 || mac > j) mac = j; if (mac < 0 || mac > j) mac = j;
if ((j <= args) && (ac < j)) { if ((j <= args) && (ac < j)) {
ac = j; ac = j;
@@ -548,30 +617,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(); PIString ret = PIStringAscii(a).trim();
int white = -1; if (readable) {
for (int i = 0; i < ret.size_s(); ++i) { int white = -1;
bool iw = ret[i] == ' ' || ret[i] == '\t' || ret[i] == '\r' || ret[i] == '\n'; for (int i = 0; i < ret.size_s(); ++i) {
//piCout << i << iw << white; bool iw = ret[i] == ' ' || ret[i] == '\t' || ret[i] == '\r' || ret[i] == '\n';
if (white < 0) { //piCout << i << iw << white;
if (iw) { if (white < 0) {
white = i; if (iw) {
continue; white = i;
} continue;
} else { }
if (!iw) { } else {
ret.replace(white, i - white, " "); if (!iw) {
i = white; ret.replace(white, i - white, " ");
white = -1; i = white;
//piCout << i; 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; return ret;
} }
@@ -589,9 +674,12 @@ void PIObject::dump(const PIString & line_prefix) const {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " properties {"; PICout(PICoutManipulators::AddNewLine) << line_prefix << " properties {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << properties_.size_s(); PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << properties_.size_s();
//printf("dump %d properties\n", properties_.size()); //printf("dump %d properties\n", properties_.size());
piForeachC (PropertyHash p, properties_) const char * o_name = "name";
if (p.first != PIString("name").hash()) auto it = properties_.makeIterator();
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << p.second.first << ": " << p.second.second; 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()); //printf("dump %d properties ok\n", properties_.size());
PICout(PICoutManipulators::AddNewLine) << line_prefix << " }"; PICout(PICoutManipulators::AddNewLine) << line_prefix << " }";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " methods {"; PICout(PICoutManipulators::AddNewLine) << line_prefix << " methods {";
@@ -606,17 +694,18 @@ void PIObject::dump(const PIString & line_prefix) const {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " connections {"; PICout(PICoutManipulators::AddNewLine) << line_prefix << " connections {";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << connections.size_s(); PICout(PICoutManipulators::AddNewLine) << line_prefix << " count: " << connections.size_s();
//printf("dump %d connections\n",connections.size()); //printf("dump %d connections\n",connections.size());
piForeachC (__Connection & c, connections) { for (const Connection & c : connections) {
PIObject * dst = c.dest_o; PIObject * dst = c.dest_o;
__MetaFunc ef = methodEH(c.signal); __MetaFunc ef = methodEH(c.signal);
PIString src(c.event); PIString src(c.event);
if (!ef.func_name.isEmpty()) if (ef.func_name)
src = ef.func_name + "(" + ef.arguments() + ")"; src = PIStringAscii(ef.func_name) + "(" + ef.arguments() + ")";
if (dst) { if (dst) {
__MetaFunc hf = dst->methodEH(c.slot); __MetaFunc hf = dst->methodEH(c.slot);
if (hf.func_name.isEmpty()) hf.func_name = "[BROKEN]"; PIString hf_fn;
else hf.func_name += "(" + hf.arguments() + ")"; if (!hf.func_name) hf_fn = "[BROKEN]";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << dst->className() << " (" << c.dest << ", \"" << dst->name() << "\")::" << hf.func_name; else hf_fn = PIStringAscii(hf.func_name) + "(" + hf.arguments() + ")";
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << dst->className() << " (" << c.dest << ", \"" << dst->name() << "\")::" << hf_fn;
} else { } else {
PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << "[lambda]"; PICout(PICoutManipulators::AddNewLine) << line_prefix << " " << src << " -> " << "[lambda]";
} }
@@ -627,7 +716,8 @@ void PIObject::dump(const PIString & line_prefix) const {
} }
void dumpApplication() { #ifndef MICRO_PIP
void dumpApplication(bool with_objects) {
PIMutexLocker _ml(PIObject::mutexObjects()); PIMutexLocker _ml(PIObject::mutexObjects());
//printf("dump application ...\n"); //printf("dump application ...\n");
PIDateTime cd = PIDateTime::current(); PIDateTime cd = PIDateTime::current();
@@ -645,23 +735,24 @@ void dumpApplication() {
PICout(PICoutManipulators::AddNewLine) << " uptime: " << PITime::fromSystemTime(cd.toSystemTime() - pi->execDateTime.toSystemTime()).toString(); PICout(PICoutManipulators::AddNewLine) << " uptime: " << PITime::fromSystemTime(cd.toSystemTime() - pi->execDateTime.toSystemTime()).toString();
PICout(PICoutManipulators::AddNewLine) << " PIObjects {"; PICout(PICoutManipulators::AddNewLine) << " PIObjects {";
PICout(PICoutManipulators::AddNewLine) << " count: " << PIObject::objects().size_s(); PICout(PICoutManipulators::AddNewLine) << " count: " << PIObject::objects().size_s();
piForeachC (PIObject * o, PIObject::objects()) if (with_objects) {
o->dump(" "); for (const PIObject * o: PIObject::objects())
o->dump(" ");
}
PICout(PICoutManipulators::AddNewLine) << " }"; PICout(PICoutManipulators::AddNewLine) << " }";
PICout(PICoutManipulators::AddNewLine) << "}"; PICout(PICoutManipulators::AddNewLine) << "}";
//printf("dump application done\n"); //printf("dump application done\n");
} }
#ifndef FREERTOS bool dumpApplicationToFile(const PIString & path, bool with_objects) {
bool dumpApplicationToFile(const PIString & path) {
PIFile f(path + "_tmp"); PIFile f(path + "_tmp");
f.setName("__S__DumpFile"); f.setName("__S__DumpFile");
f.clear(); f.clear();
if (!f.open(PIIODevice::WriteOnly)) return false; if (!f.open(PIIODevice::WriteOnly)) return false;
bool ba = PICout::isBufferActive(); bool ba = PICout::isBufferActive();
PICout::setBufferActive(true, true); PICout::setBufferActive(true, true);
dumpApplication(); dumpApplication(with_objects);
f << PICout::buffer(); f << PICout::buffer();
f.close(); f.close();
PICout::setBufferActive(ba, true); PICout::setBufferActive(ba, true);
@@ -671,7 +762,7 @@ bool dumpApplicationToFile(const PIString & path) {
#endif #endif
void PIObject::__MetaData::addScope(const PIString & s, uint shash) { void PIObject::__MetaData::addScope(const char * s, uint shash) {
if (!scope_id.contains(shash)) { if (!scope_id.contains(shash)) {
scope_list << s; scope_list << s;
scope_id << shash; scope_id << shash;
@@ -679,41 +770,87 @@ void PIObject::__MetaData::addScope(const PIString & s, uint shash) {
} }
void PIObject::__Connection::destroy() {
void PIObject::Connection::destroy() {
if (functor) delete functor; if (functor) delete functor;
functor = nullptr; 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) PRIVATE_DEFINITION_START(PIObject::Deleter)
PIThread thread; PIThread thread;
PIConditionVariable cond_var; PIConditionVariable cond_var;
PIMutex cond_mutex, queue_mutex;
PIVector<PIObject*> obj_queue; PIVector<PIObject*> obj_queue;
PRIVATE_DEFINITION_END(PIObject::Deleter) PRIVATE_DEFINITION_END(PIObject::Deleter)
PIObject::Deleter::Deleter() { PIObject::Deleter::Deleter() {
//piCout << "Deleter start ..."; //piCout << "Deleter start ...";
stopping = started = posted = false; PRIVATE->thread.setSlot([this](){
CONNECTL(&(PRIVATE->thread), started, [this](){proc();}); PIVector<PIObject*> oq;
PRIVATE->thread.startOnce(); PRIVATE->thread.lock();
while (!started) while(PRIVATE->obj_queue.isEmpty()) PRIVATE->cond_var.wait(PRIVATE->thread.mutex());
piMSleep(1); oq.swap(PRIVATE->obj_queue);
PRIVATE->thread.unlock();
for (PIObject * o : oq) deleteObject(o);
});
PRIVATE->thread.start();
} }
PIObject::Deleter::~Deleter() { PIObject::Deleter::~Deleter() {
//piCout << "~Deleter ..."; //piCout << "~Deleter ...";
stopping = true; PRIVATE->thread.stop();
PRIVATE->cond_var.notifyAll(); PRIVATE->cond_var.notifyAll();
#ifndef WINDOWS PRIVATE->thread.waitForFinish();
while (PRIVATE->thread.isRunning()) for (PIObject * o : PRIVATE->obj_queue) deleteObject(o);
piMSleep(1);
#endif
deleteAll();
//piCout << "~Deleter ok"; //piCout << "~Deleter ok";
} }
@@ -727,46 +864,13 @@ PIObject::Deleter * PIObject::Deleter::instance() {
void PIObject::Deleter::post(PIObject * o) { void PIObject::Deleter::post(PIObject * o) {
if (!o->isPIObject()) return; if (!o->isPIObject()) return;
//piCout << "[Deleter] post" << o << "..."; //piCout << "[Deleter] post" << o << "...";
PRIVATE->queue_mutex.lock(); PRIVATE->thread.lock();
if (!PRIVATE->obj_queue.contains(o)) if (!PRIVATE->obj_queue.contains(o)) {
PRIVATE->obj_queue << o; PRIVATE->obj_queue << o;
PRIVATE->queue_mutex.unlock(); PRIVATE->cond_var.notifyAll();
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();
} }
//piCout << "[Deleter] proc end ok"; PRIVATE->thread.unlock();
} //piCout << "[Deleter] post" << o << "done";
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);
} }
@@ -774,12 +878,9 @@ void PIObject::Deleter::deleteObject(PIObject * o) {
//piCout << "[Deleter] delete" << (uintptr_t)o << "..."; //piCout << "[Deleter] delete" << (uintptr_t)o << "...";
if (o->isPIObject()) { if (o->isPIObject()) {
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ..."; //piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic ...";
while (o->isInEvent()) { while (o->isInEvent()) piMinSleep();
piMSleep(1);
}
//piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done"; //piCout << "[Deleter] delete" << (uintptr_t)o << "wait atomic done";
if (o->isPIObject()) delete o;
delete o;
} }
//piCout << "[Deleter] delete" << (uintptr_t)o << "done"; //piCout << "[Deleter] delete" << (uintptr_t)o << "done";
} }

View File

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

View File

@@ -1,7 +1,8 @@
/*! @file piobject_macros.h /*! \file piobject_macros.h
* @brief Base object * \ingroup Core
* * \~\brief
* This file declare macros for PIObject * \~english PIObject macros
* \~russian Макросы PIObject
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -29,67 +30,127 @@
#ifdef DOXYGEN #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) #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) #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() #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) #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) #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) #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) #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 #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() #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) #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) #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) #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) #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 #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(); #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); #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); #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); #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); #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 #define EVENT EVENT0
@@ -101,81 +162,217 @@
#define RAISE_EVENT RAISE_EVENT0 #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) #define CONNECTU(src, event, dest, handler)
/// \relatesalso PIObject @brief connect event \"event\" from object \"src\" to event handler \"handler\". //! \relatesalso PIObject
/// Event handler will be executed by \"performer\". \"Event\" and \"handler\" must has equal argument lists. //! \~\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) #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) #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) #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) #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) #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) #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) #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 #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) #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) #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) #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) #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) #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 #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) #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) #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) #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) #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) #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 #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 HANDLER(handler)
#define PIOBJECT(name)
#define PIOBJECT_SUBCLASS(name)
#else #else
@@ -188,13 +385,14 @@
# define __PTYPE(t) __PIVariantTypeInfo__<t>::PureType # define __PTYPE(t) __PIVariantTypeInfo__<t>::PureType
#endif #endif
#define __VVALUE(t, v) v.value< __PTYPE(t) >() #define __VVALUE(t, v) v.value< __PTYPE(t) >()
#define __PIOBJECT_MAX_ARGS__ 4
#define PIOBJECT(name) \ #define PIOBJECT(name) \
protected: \ protected: \
typedef name __PIObject__; \ typedef name __PIObject__; \
public: \ 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;} \ static uint __classNameIDS() {static uint ret = PIStringAscii(#name).hash(); return ret;} \
virtual const char * className() const {return #name;} \ virtual const char * className() const {return #name;} \
virtual uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \ virtual uint classNameID() const {static uint ret = PIStringAscii(#name).hash(); return ret;} \
@@ -214,7 +412,7 @@
__MetaData & eh(__meta_data()[id]); \ __MetaData & eh(__meta_data()[id]); \
eh.eh_set << ehp.eh_set; \ eh.eh_set << ehp.eh_set; \
eh.eh_func << ehp.eh_func; \ eh.eh_func << ehp.eh_func; \
eh.addScope(__classNameS(), id); \ eh.addScope(__classNameCC(), id); \
} \ } \
}; \ }; \
__BaseInitializer__ __base_init__; __BaseInitializer__ __base_init__;
@@ -234,7 +432,7 @@
eh.eh_func << ehp.eh_func; \ eh.eh_func << ehp.eh_func; \
eh.scope_id = ehp.scope_id; \ eh.scope_id = ehp.scope_id; \
eh.scope_list = ehp.scope_list; \ eh.scope_list = ehp.scope_list; \
eh.addScope(__classNameS(), id); \ eh.addScope(__classNameCC(), id); \
} \ } \
}; \ }; \
__ParentInitializer__ __parent_init__; \ __ParentInitializer__ __parent_init__; \
@@ -246,92 +444,61 @@
#define PIOBJECT_SUBCLASS(name, parent) PIOBJECT(name) PIOBJECT_PARENT(parent) #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) \ #define EH_INIT0(ret, name) \
STATIC_INITIALIZER_BEGIN \ STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*))__stat_eh_##name##__; \ void * fp = (void*)(ret(*)(void*))__stat_eh_##name##__; \
void * fpV = fp; \ void * fpV = fp; \
if (eh.eh_set[fp]) return; \ __EH_INIT_BASE__(ret, name) \
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); \
STATIC_INITIALIZER_END STATIC_INITIALIZER_END
#define EH_INIT1(ret, name, a0, n0) \ #define EH_INIT1(ret, name, a0, n0) \
STATIC_INITIALIZER_BEGIN \ STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0))__stat_eh_##name##__; \ void * fp = (void*)(ret(*)(void*, a0))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &))__stat_eh_v_##name##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \ __EH_INIT_BASE__(ret, name) \
eh.eh_set << fp; \ f.__addArgument(#a0, #n0); \
__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); \
STATIC_INITIALIZER_END STATIC_INITIALIZER_END
#define EH_INIT2(ret, name, a0, n0, a1, n1) \ #define EH_INIT2(ret, name, a0, n0, a1, n1) \
STATIC_INITIALIZER_BEGIN \ STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1))__stat_eh_##name##__; \ void * fp = (void*)(ret(*)(void*, a0, a1))__stat_eh_##name##__; \
void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &, const PIVariantSimple &))__stat_eh_v_##name##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \ __EH_INIT_BASE__(ret, name) \
eh.eh_set << fp; \ f.__addArgument(#a0, #n0); \
__MetaFunc & f(eh.eh_func[fp]); \ f.__addArgument(#a1, #n1); \
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); \
STATIC_INITIALIZER_END STATIC_INITIALIZER_END
#define EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \ #define EH_INIT3(ret, name, a0, n0, a1, n1, a2, n2) \
STATIC_INITIALIZER_BEGIN \ STATIC_INITIALIZER_BEGIN \
PIMutexLocker ml(__meta_mutex()); \
__MetaData & eh(__meta_data()[__classNameIDS()]); \
void * fp = (void*)(ret(*)(void*, a0, a1, a2))__stat_eh_##name##__; \ 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##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &, const PIVariantSimple &, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \ __EH_INIT_BASE__(ret, name) \
eh.eh_set << fp; \ f.__addArgument(#a0, #n0); \
__MetaFunc & f(eh.eh_func[fp]); \ f.__addArgument(#a1, #n1); \
f.scope = __classNameS(); \ f.__addArgument(#a2, #n2); \
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); \
STATIC_INITIALIZER_END STATIC_INITIALIZER_END
#define EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \ #define EH_INIT4(ret, name, a0, n0, a1, n1, a2, n2, a3, n3) \
STATIC_INITIALIZER_BEGIN \ 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 * 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##__; \ void * fpV = (void*)(ret(*)(void*, const PIVariantSimple &, const PIVariantSimple &, const PIVariantSimple &, const PIVariantSimple &))__stat_eh_v_##name##__; \
if (eh.eh_set[fp]) return; \ __EH_INIT_BASE__(ret, name) \
eh.eh_set << fp; \ f.__addArgument(#a0, #n0); \
__MetaFunc & f(eh.eh_func[fp]); \ f.__addArgument(#a1, #n1); \
f.scope = __classNameS(); \ f.__addArgument(#a2, #n2); \
f.func_name = PIStringAscii(#name); \ f.__addArgument(#a3, #n3); \
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); \
STATIC_INITIALIZER_END STATIC_INITIALIZER_END

View File

@@ -20,6 +20,33 @@
#include "pipropertystorage.h" #include "pipropertystorage.h"
//! \~\class PIPropertyStorage pipropertystorage.h
//! \~\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
//!
//! \~\class PIPropertyStorage::Property pipropertystorage.h
//! \~\details
//!
bool PIPropertyStorage::isPropertyExists(const PIString & _name) const { bool PIPropertyStorage::isPropertyExists(const PIString & _name) const {
for (uint i = 0; i < props.size(); ++i) for (uint i = 0; i < props.size(); ++i)
if (props[i].name == _name) if (props[i].name == _name)
@@ -28,6 +55,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) { bool PIPropertyStorage::addProperty(const PIPropertyStorage::Property & p) {
for (uint i = 0; i < props.size(); ++i) for (uint i = 0; i < props.size(); ++i)
if (props[i].name == p.name) { if (props[i].name == p.name) {
@@ -50,6 +80,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) { bool PIPropertyStorage::addProperty(const PIString & _name, const PIVariant & _def_value, const PIString & _comment, int _flags) {
return addProperty(Property(_name, _comment, _def_value, _flags)); return addProperty(Property(_name, _comment, _def_value, _flags));
} }
@@ -66,6 +99,9 @@ bool PIPropertyStorage::removeProperty(const PIString & _name) {
} }
//! \details
//! \~english "flag" checked as bitfield
//! \~russian "flag" проверяется как битовое поле
int PIPropertyStorage::removePropertiesByFlag(int flag) { int PIPropertyStorage::removePropertiesByFlag(int flag) {
int ret = 0; int ret = 0;
for (int i = 0; i < props.size_s(); ++i) { for (int i = 0; i < props.size_s(); ++i) {
@@ -79,6 +115,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) { void PIPropertyStorage::updateProperties(const PIVector<PIPropertyStorage::Property> & properties_, int flag_ignore) {
PIMap<PIString, PIVariant> values; PIMap<PIString, PIVariant> values;
piForeachC(Property & p, props) piForeachC(Property & p, props)

View File

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

View File

@@ -27,99 +27,39 @@
#ifdef WINDOWS #ifdef WINDOWS
# include <stringapiset.h> # include <stringapiset.h>
#endif #endif
#include <wchar.h> #include <string>
#ifdef ANDROID #include <locale>
# if __ANDROID_API__ < 21 #include <codecvt>
# define wctomb(s, wc) wcrtomb(s, wc, NULL)
# define mbtowc(pwc, s, n) mbrtowc(pwc, s, n, NULL)
# endif
#endif
/*! \class PIString //! \class PIString pistring.h
* @brief String class //! \~\details
* \details PIP use this class for use string information. //! \~english \section PIString_sec0 Synopsis
* //! \~russian \section PIString_sec0 Краткий обзор
* \section PIString_sec0 Synopsis //!
* This class based on \a PIVector to store information. //! \~english
* String is a sequence of \a PIChar and can contain multibyte //! String is a sequence of \a PIChar. Real memory size of string is symbols count * 2.
* symbols. Therefore real memory size of string is symbols count * 4. //! String can be constucted from many types of data and can be converted
* 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
* to many types. There are man operators and handly functions to use //! string as you wish.
* string as you wish. //!
* //! \~russian
* \section PIString_sec1 To/from data convertions //! Строка состоит из последовательности \a PIChar. Реальный объем памяти,
* Most common constructor is \a PIString(const char * str), where "str" //! занимаемый строкой, равен количеству символов * 2. Строка может быть
* 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().
*
*/
/*! \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', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^'}; '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,
-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, -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, 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, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
@@ -138,35 +78,21 @@ const float PIString::ElideCenter = .5f;
const float PIString::ElideRight = 1.f; const float PIString::ElideRight = 1.f;
#ifndef CC_VC #define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); snprintf(ch, 256, f, v); return PIStringAscii(ch);
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf(ch, f, v);
#else PIString PIString::itos(const int num) {pisprintf("%d", num);}
# define pisprintf(f, v) char ch[256]; memset(ch, 0, 256); sprintf_s(ch, 256, f, v); PIString PIString::ltos(const long num) {pisprintf("%ld", num);}
#endif PIString PIString::lltos(const llong num) {pisprintf("%lld", num);}
#ifdef ANDROID PIString PIString::uitos(const uint num) {pisprintf("%u", num);}
//int wctomb(char * c, wchar_t w) {*c = ((char * )&w)[0]; return 1;} PIString PIString::ultos(const ulong num) {pisprintf("%lu", num);}
#endif PIString PIString::ulltos(const ullong num) {pisprintf("%llu", num);}
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);
}
PIString PIString::dtos(const double num, char format, int precision) { PIString PIString::dtos(const double num, char format, int precision) {
char f[8] = "%."; 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[2 + wr] = format;
f[3 + wr] = 0; f[3 + wr] = 0;
pisprintf(f, num); pisprintf(f, num);
return PIString(ch);
} }
#undef pisprintf #undef pisprintf
@@ -174,7 +100,10 @@ PIString PIString::dtos(const double num, char format, int precision) {
PIString PIString::fromNumberBaseS(const llong value, int base, bool * ok) { PIString PIString::fromNumberBaseS(const llong value, int base, bool * ok) {
if (value == 0LL) return PIString('0'); 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 (ok != 0) *ok = true;
if (base == 10) return lltos(value); if (base == 10) return lltos(value);
PIString ret; PIString ret;
@@ -193,7 +122,10 @@ PIString PIString::fromNumberBaseS(const llong value, int base, bool * ok) {
PIString PIString::fromNumberBaseU(const ullong value, int base, bool * ok) { PIString PIString::fromNumberBaseU(const ullong value, int base, bool * ok) {
if (value == 0ULL) return PIString('0'); 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 (ok != 0) *ok = true;
if (base == 10) return ulltos(value); if (base == 10) return ulltos(value);
PIString ret; PIString ret;
@@ -215,17 +147,26 @@ llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
PIString v = value.trimmed(); PIString v = value.trimmed();
if (base < 0) { if (base < 0) {
int ind = v.find(s_0x); int ind = v.find(s_0x);
if (ind == 0 || ind == 1) {v.remove(ind, 2); base = 16;} if (ind == 0 || ind == 1) {
else base = 10; v.remove(ind, 2);
} else base = 16;
if (base < 2 || base > 40) {if (ok != 0) *ok = false; return 0;} } else {
base = 10;
}
} else if ((base < 2) || (base > 40)) {
if (ok != 0) *ok = false;
return 0;
}
if (ok) *ok = true; if (ok) *ok = true;
PIVector<int> digits; PIVector<int> digits;
llong ret = 0, m = 1; llong ret = 0, m = 1;
bool neg = false; bool neg = false;
int cs; char cs;
for (int i = 0; i < v.size_s(); ++i) { 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())]; cs = fromBaseN[int(v[i].toAscii())];
if (cs < 0 || cs >= base) { if (cs < 0 || cs >= base) {
if (ok) *ok = false; if (ok) *ok = false;
@@ -243,113 +184,87 @@ llong PIString::toNumberBase(const PIString & value, int base, bool * ok) {
void PIString::appendFromChars(const char * c, int s, const char * codepage) { void PIString::appendFromChars(const char * c, int s, const char * codepage) {
if (s <= 0) return; // piCout << "appendFromChars";
int sz; if (s == 0) return;
int old_sz = size_s();
if (s == -1) s = strlen(c);
#ifdef PIP_ICU #ifdef PIP_ICU
UErrorCode e((UErrorCode)0); UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(codepage, &e); UConverter * cc = ucnv_open(codepage, &e);
if (cc) { if (cc) {
UChar * ucs = new UChar[s]; d.enlarge(s);
memset(ucs, 0, s * sizeof(UChar));
e = (UErrorCode)0; e = (UErrorCode)0;
int sz = ucnv_toUChars(cc, ucs, s, c, s, &e); int sz = ucnv_toUChars(cc, (UChar*)(d.data(old_sz)), s, c, s, &e);
//printf("appendFromChars %d -> %d\n", s, sz); d.resize(old_sz+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;
ucnv_close(cc); ucnv_close(cc);
return; return;
} }
#else #else
# ifdef WINDOWS # 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; if (sz <= 0) return;
int old_sz = size_s(); d.enlarge(sz);
enlarge(sz); MultiByteToWideChar((uint)(uintptr_t)codepage, MB_ERR_INVALID_CHARS, c, s, (LPWSTR)d.data(old_sz), 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);
# else # else
wchar_t wc; std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> ucs2conv;
mbtowc(0,0,0); // reset mbtowc std::u16string ucs2 = ucs2conv.from_bytes(c, c+s);
//qDebug() << "FromChars ..."; d.enlarge(ucs2.size());
while (s>0) { ucs2.copy((char16_t *)d.data(old_sz), ucs2.size());
//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();
# endif # endif
#endif #endif
} }
PIString PIString::fromConsole(const char * s) { PIString PIString::fromConsole(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret; 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; return ret;
} }
PIString PIString::fromSystem(const char * s) { PIString PIString::fromSystem(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret; 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; return ret;
} }
PIString PIString::fromUTF8(const char * s) { PIString PIString::fromUTF8(const char * s) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret; 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; return ret;
} }
PIString PIString::fromUTF8(const PIByteArray & ba) { PIString PIString::fromUTF8(const PIByteArray & ba) {
PIString ret; PIString ret;
if (ba.isEmpty()) return ret; if (ba.isNotEmpty()) ret.appendFromChars((const char*)ba.data(), ba.size(), __utf8name__);
ret.appendFromChars((const char*)ba.data(), ba.size(), __utf8name__);
return ret; return ret;
} }
PIString PIString::fromAscii(const char * s) { PIString PIString::fromAscii(const char * s) {
PIString ret; return fromAscii(s, strlen(s));
int l = 0;
while (s[l] != '\0') {
ret.push_back(PIChar(s[l]));
++l;
}
return ret;
} }
PIString PIString::fromAscii(const char * s, int len) { PIString PIString::fromAscii(const char * s, int len) {
PIString ret; PIString ret;
for (int l = 0; l < len; ++l) ret.resize(len);
ret.push_back(PIChar(s[l])); for (int l = 0; l < len; ++l) {
ret[l] = s[l];
}
return ret; return ret;
} }
PIString PIString::fromCodepage(const char * s, const char * c) { PIString PIString::fromCodepage(const char * s, const char * c) {
int l = 0;
while (s[l] != '\0') ++l;
PIString ret; PIString ret;
if (l > 0) ret.appendFromChars(s, l if (s[0] > '\0') ret.appendFromChars(s, -1
#ifdef PIP_ICU #ifdef PIP_ICU
, c , c
#else #else
@@ -362,6 +277,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 PIString::readableSize(llong bytes) {
PIString s; PIString s;
s.setReadableSize(bytes); s.setReadableSize(bytes);
@@ -370,107 +298,78 @@ PIString PIString::readableSize(llong bytes) {
void PIString::buildData(const char * cp) const { void PIString::buildData(const char * cp) const {
data_.clear(); deleteData();
int sz = 0;
#ifdef PIP_ICU #ifdef PIP_ICU
UErrorCode e((UErrorCode)0); UErrorCode e((UErrorCode)0);
UConverter * cc = ucnv_open(cp, &e); UConverter * cc = ucnv_open(cp, &e);
if (cc) { if (cc) {
char uc[8]; const size_t len = MB_CUR_MAX*size()+1;
data_.reserve(size_s()); data_ = (char *)malloc(len);
for (int i = 0; i < size_s(); ++i) { int sz = ucnv_fromUChars(cc, data_, len, (const UChar*)(d.data()), d.size_s(), &e);
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]);
}
}
ucnv_close(cc); ucnv_close(cc);
data_.push_back('\0'); data_[sz] = '\0';
return; return;
} }
#else #else
# ifdef WINDOWS # ifdef WINDOWS
sz = WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), 0, 0, NULL, NULL); int sz = WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)d.data(), d.size_s(), 0, 0, NULL, NULL);
//printf("WideCharToMultiByte %d %d\n", (uint)(uintptr_t)cp, sz);
if (sz <= 0) { if (sz <= 0) {
//printf("WideCharToMultiByte erro %d\n", GetLastError()); data_ = (char *)malloc(1);
data_.push_back(uchar('\0')); data_[0] = '\0';
return; return;
} }
data_.resize(sz); data_ = (char *)malloc(sz+1);
WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)PIDeque<PIChar>::data(), PIDeque<PIChar>::size_s(), (LPSTR)data_.data(), data_.size_s(), NULL, NULL); WideCharToMultiByte((uint)(uintptr_t)cp, 0, (LPCWCH)d.data(), d.size_s(), (LPSTR)data_, sz, NULL, NULL);
data_.push_back(uchar('\0')); data_[sz] = '\0';
return; return;
# else # else
wchar_t wc; std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> ucs2conv;
char tc[8]; std::string u8str = ucs2conv.to_bytes((char16_t*)d.data(), (char16_t*)d.data() + d.size());
wctomb(0, 0); data_ = (char *)malloc(u8str.size()+1);
for (int i = 0; i < size_s(); ++i) { strcpy(data_, u8str.c_str());
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'));
# endif # endif
#endif #endif
} }
void PIString::deleteData() const {
if (!data_) return;
free(data_);
data_ = nullptr;
}
void PIString::trimsubstr(int &st, int &fn) const { void PIString::trimsubstr(int &st, int &fn) const {
for (int i = 0; i < length(); ++i) 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)) if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0)) {
{st = i; break;} st = i;
break;
}
}
if (st < 0) return; if (st < 0) return;
for (int i = length() - 1; i >= 0; --i) 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)) if (at(i) != ' ' && at(i) != '\t' && at(i) != '\n' && at(i) != '\r' && at(i) != char(12) && at(i) != uchar(0)) {
{fn = i; break;} 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();
} }
uint PIString::hash() const { 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 { PIByteArray PIString::toUTF8() const {
if (isEmpty()) return data_.resized(0); if (isEmpty()) return PIByteArray();
buildData(__utf8name__); buildData(__utf8name__);
return data_.resized(data_.size_s() - 1); return PIByteArray(data_, strlen(data_));
} }
PIByteArray PIString::toCharset(const char * c) const { PIByteArray PIString::toCharset(const char * c) const {
if (isEmpty()) return data_.resized(0); if (isEmpty()) return PIByteArray();
buildData( buildData(
#ifdef PIP_ICU #ifdef PIP_ICU
c c
@@ -480,62 +379,67 @@ PIByteArray PIString::toCharset(const char * c) const {
# endif # endif
#endif #endif
); );
return data_.resized(data_.size_s() - 1); return PIByteArray(data_, strlen(data_));
} }
PIString & PIString::operator +=(const char * str) { PIString & PIString::operator +=(const char * str) {
if (!str) return *this; if (!str) return *this;
int l = 0; appendFromChars(str, -1, __syslocname__);
while (str[l] != '\0') ++l;
appendFromChars(str, l, __syslocname__);
return *this; return *this;
} }
PIString::~PIString() {
deleteData();
}
PIString & PIString::operator +=(const wchar_t * str) { PIString & PIString::operator +=(const wchar_t * str) {
if (!str) return *this; if (!str) return *this;
int i = -1; int i = -1;
while (str[++i]) while (str[++i]) {
push_back(PIChar(ushort(str[i]))); d.push_back(PIChar(str[i]));
}
return *this; return *this;
} }
PIString & PIString::operator +=(const PIString & str) { 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; return *this;
} }
bool PIString::operator ==(const PIString & str) const { bool PIString::operator ==(const PIString & str) const {
uint l = str.size(); return d == str.d;
if (size() != l) return false;
for (uint i = 0; i < l; ++i)
if (str[i] != at(i))
return false;
return true;
} }
bool PIString::operator !=(const PIString & str) const { bool PIString::operator !=(const PIString & str) const {
uint l = str.size(); return d != str.d;
if (size() != l) return true;
for (uint i = 0; i < l; ++i)
if (str[i] != at(i))
return true;
return false;
} }
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 true; if (size() < l) return true;
if (size() > l) return false; if (size() > l) return false;
for (uint i = 0; i < l; ++i) { for (size_t i = 0; i < l; ++i) {
if (at(i) == str[i]) continue; if (at(i) == str.at(i)) continue;
if (at(i) < str[i]) return true; if (at(i) < str.at(i)) return true;
else return false; else return false;
} }
return false; return false;
@@ -543,18 +447,33 @@ bool PIString::operator <(const PIString & str) const {
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 false;
if (size() > l) return true; if (size() > l) return true;
for (uint i = 0; i < l; ++i) { for (size_t i = 0; i < l; ++i) {
if (at(i) == str[i]) continue; if (at(i) == str.at(i)) continue;
if (at(i) < str[i]) return false; if (at(i) < str.at(i)) return false;
else return true; else return true;
} }
return false; 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 PIString::mid(const int start, const int len) const {
//PIString str; //PIString str;
int s = start, l = len; int s = start, l = len;
@@ -564,16 +483,26 @@ PIString PIString::mid(const int start, const int len) const {
s = 0; s = 0;
} }
if (l < 0) { if (l < 0) {
return PIString(&(at(s)), size_s() - s); return PIString(d.data(s), size_s() - s);
} else { } else {
if (l > length() - s) if (l > length() - s) l = length() - s;
l = length() - s; return PIString(d.data(s), l);
return PIString(&(at(s)), l);
} }
return PIString(); 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) { PIString & PIString::cutMid(const int start, const int len) {
int s = start, l = len; int s = start, l = len;
if (l == 0) return *this; if (l == 0) return *this;
@@ -581,17 +510,26 @@ PIString & PIString::cutMid(const int start, const int len) {
l += s; l += s;
s = 0; s = 0;
} }
if (l < 0) if (l < 0) {
remove(s, size() - s); d.remove(s, size() - s);
else { } else {
if (l > length() - s) if (l > length() - s) l = length() - s;
l = length() - s; d.remove(s, l);
remove(s, l);
} }
return *this; 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() { PIString & PIString::trim() {
int st = -1, fn = 0; int st = -1, fn = 0;
trimsubstr(st, fn); trimsubstr(st, fn);
@@ -613,18 +551,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) { PIString & PIString::replace(int from, int count, const PIString & with) {
count = piMini(count, length() - from); count = piMini(count, length() - from);
if (count == with.size_s()) if (count == with.size_s()) {
memcpy(PIDeque<PIChar>::data(from), static_cast<PIDeque<PIChar>>(with).data(), count * sizeof(PIChar)); memcpy(d.data(from), with.d.data(), count * sizeof(PIChar));
else { } else {
remove(from, count); d.remove(from, count);
PIDeque<PIChar>::insert(from, with); d.insert(from, with.d);
} }
return *this; 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) { PIString & PIString::replace(const PIString & what, const PIString & with, bool * ok) {
if (what.isEmpty()) { if (what.isEmpty()) {
if (ok != 0) *ok = false; if (ok != 0) *ok = false;
@@ -637,10 +596,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) { PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
if (what.isEmpty() || what == with) return *this; if (what.isEmpty() || what == with) return *this;
if (with.isEmpty()) removeAll(what); if (with.isEmpty()) {
else { removeAll(what);
} else {
int l = what.length(), dl = with.length() - what.length(); int l = what.length(), dl = with.length() - what.length();
for (int i = 0; i < length() - l + 1; ++i) { for (int i = 0; i < length() - l + 1; ++i) {
bool match = true; bool match = true;
@@ -651,16 +618,22 @@ PIString & PIString::replaceAll(const PIString & what, const PIString & with) {
} }
} }
if (!match) continue; if (!match) continue;
if (dl > 0) PIDeque<PIChar>::insert(i, PIDeque<PIChar>((size_t)dl)); if (dl > 0) d.insert(i, PIDeque<PIChar>((size_t)dl));
if (dl < 0) PIDeque<PIChar>::remove(i, -dl); if (dl < 0) d.remove(i, -dl);
memcpy(PIDeque<PIChar>::data(i), &(with.at(0)), with.length() * sizeof(PIChar)); memcpy(d.data(i), with.d.data(), with.size() * sizeof(PIChar));
//i -= l;
} }
} }
return *this; 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) { PIString & PIString::replaceAll(const PIString & what, const char with) {
if (what.isEmpty()) return *this; if (what.isEmpty()) return *this;
int l = what.length(), dl = what.length() - 1; int l = what.length(), dl = what.length() - 1;
@@ -673,19 +646,24 @@ PIString & PIString::replaceAll(const PIString & what, const char with) {
} }
} }
if (!match) continue; if (!match) continue;
if (dl > 0) PIDeque<PIChar>::remove(i, dl); if (dl > 0) d.remove(i, dl);
(*this)[i] = PIChar(with); d[i] = PIChar(with);
//i -= l;
} }
return *this; 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) { PIString & PIString::replaceAll(const char what, const char with) {
int l = length(); int l = length();
for (int i = 0; i < l; ++i) { for (int i = 0; i < l; ++i) {
if (at(i) == what) if (at(i) == what) d[i] = with;
(*this)[i] = with;
} }
return *this; return *this;
} }
@@ -697,13 +675,13 @@ PIString & PIString::removeAll(const PIString & str) {
for (int i = 0; i < length() - l + 1; ++i) { for (int i = 0; i < length() - l + 1; ++i) {
bool match = true; bool match = true;
for (int j = 0; j < l; ++j) { for (int j = 0; j < l; ++j) {
if (at(j + i) != str[j]) { if (d.at(j + i) != str.at(j)) {
match = false; match = false;
break; break;
} }
} }
if (!match) continue; if (!match) continue;
PIDeque<PIChar>::remove(i, l); d.remove(i, l);
i -= l; i -= l;
} }
return *this; return *this;
@@ -711,7 +689,7 @@ PIString & PIString::removeAll(const PIString & str) {
PIString & PIString::insert(int index, 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; return *this;
} }
@@ -726,8 +704,8 @@ PIString & PIString::elide(int size, float pos) {
pos = piClampf(pos, 0.f, 1.f); pos = piClampf(pos, 0.f, 1.f);
int ns = size - 2; int ns = size - 2;
int ls = piRoundf(ns * pos); int ls = piRoundf(ns * pos);
remove(ls, length() - ns); d.remove(ls, length() - ns);
insert(ls, s_dotdot); d.insert(ls, s_dotdot.d);
return *this; return *this;
} }
@@ -747,73 +725,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 { int PIString::find(const char c, const int start) const {
for (int i = start; i < length(); ++i) for (int i = start; i < length(); ++i) {
if (at(i) == c) if (at(i) == c) return i;
return i; }
return -1; 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 PIString::find(const PIString & str, const int start) const {
int l = str.length(); int l = str.length();
for (int i = start; i < length() - l + 1; ++i) for (int i = start; i < length() - l + 1; ++i) {
if (mid(i, l) == str) if (mid(i, l) == str) return i;
return i; }
return -1; 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 { int PIString::findLast(const char c, const int start) const {
for (int i = length() - 1; i >= start; --i) for (int i = length() - 1; i >= start; --i) {
if (at(i) == c) if (at(i) == c) return i;
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; 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 PIString::findLast(const PIString & str, const int start) const {
int l = str.length(); int l = str.length();
for (int i = length() - l; i >= start; --i) for (int i = length() - l; i >= start; --i) {
if (mid(i, l) == str) if (mid(i, l) == str) return i;
return i; }
return -1; 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 PIString::findWord(const PIString & word, const int start) const {
int f = start - 1, tl = length(), wl = word.length(); int f = start - 1, tl = length(), wl = word.length();
while ((f = find(word, f + 1)) >= 0) { while ((f = find(word, f + 1)) >= 0) {
bool ok = true; bool ok = true;
PIChar c; PIChar c;
if (f > 0) {c = (*this)[f - 1]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}} if (f > 0) {
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {ok = false; continue;}} 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; if (ok) return f;
} }
return -1; 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 PIString::findCWord(const PIString & word, const int start) const {
int f = start - 1, tl = length(), wl = word.length(); int f = start - 1, tl = length(), wl = word.length();
while ((f = find(word, f + 1)) >= 0) { while ((f = find(word, f + 1)) >= 0) {
bool ok = true; bool ok = true;
PIChar c; 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 > 0) {
if (f + wl < tl) {c = (*this)[f + wl]; if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || (c != '_' && !c.isAlpha() && !c.isDigit()))) {ok = false; continue;}} 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; if (ok) return f;
} }
return -1; 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 { int PIString::findRange(const PIChar start, const PIChar end, const PIChar shield, const int start_index, int * len) const {
if (len) *len = 0; if (len) *len = 0;
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end); bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
int sz = size_s(), ls = -1, le = -1, cnt = 0; int sz = size_s(), ls = -1, le = -1, cnt = 0;
for (int i = start_index; i < sz; ++i) { for (int i = start_index; i < sz; ++i) {
PIChar c = at(i); PIChar c = at(i);
if (c == shield) {++i; continue;} if (c == shield) {
++i;
continue;
}
if (trim_) { if (trim_) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue; continue;
@@ -844,26 +950,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 PIString::entries(const PIChar c) const {
int sz = size_s(), ret = 0; 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; if (at(i) == c) ++ret;
}
return ret; return ret;
} }
@@ -880,6 +971,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 { bool PIString::toBool() const {
static const PIString s_true = PIStringAscii("true"); static const PIString s_true = PIStringAscii("true");
static const PIString s_yes = PIStringAscii("yes" ); static const PIString s_yes = PIStringAscii("yes" );
@@ -893,13 +995,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 PIString::takeSymbol() {
PIString ret; PIString ret;
int sz = size_s(), ss = -1; int sz = size_s(), ss = -1;
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
PIChar c = at(i); PIChar c = at(i);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') if (c == ' ' || c == '\t' || c == '\n' || c == '\r') continue;
continue;
ss = i; ss = i;
break; break;
} }
@@ -910,6 +1020,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() { PIString PIString::takeWord() {
int sz = size_s(), ws = -1, we = -1; int sz = size_s(), ws = -1, we = -1;
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
@@ -930,6 +1049,10 @@ PIString PIString::takeWord() {
} }
//! \~\details
//! \~\code
//! \endcode
//! \~\sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber(), \a takeRange()
PIString PIString::takeCWord() { PIString PIString::takeCWord() {
PIString ret; PIString ret;
int sz = size_s(), ws = -1, we = -1; int sz = size_s(), ws = -1, we = -1;
@@ -942,10 +1065,11 @@ PIString PIString::takeCWord() {
} }
} else { } else {
if (ws < 0) { if (ws < 0) {
if (c.isAlpha() || c == '_') if (c.isAlpha() || c == '_') {
ws = i; ws = i;
else } else {
return ret; return ret;
}
} else { } else {
if (!c.isAlpha() && !c.isDigit() && c != '_') { if (!c.isAlpha() && !c.isDigit() && c != '_') {
we = i; we = i;
@@ -961,6 +1085,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() { PIString PIString::takeLine() {
int sz = size_s(), le = -1; int sz = size_s(), le = -1;
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
@@ -971,14 +1104,26 @@ PIString PIString::takeLine() {
} }
} }
PIString ret = left(le); PIString ret = left(le);
if (!ret.isEmpty()) if (!ret.isEmpty()) {
if (ret.back() == '\r') if (ret.back() == '\r') {
ret.cutRight(1); ret.cutRight(1);
}
}
cutLeft(le < 0 ? sz : le + 1); cutLeft(le < 0 ? sz : le + 1);
return ret; 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 PIString::takeNumber() {
PIString ret; PIString ret;
int sz = size_s(), ls = -1, le = -1, phase = 0; int sz = size_s(), ls = -1, le = -1, phase = 0;
@@ -988,37 +1133,75 @@ PIString PIString::takeNumber() {
//piCout << "char " << c << "phase" << phase; //piCout << "char " << c << "phase" << phase;
switch (phase) { switch (phase) {
case 0: // trim case 0: // trim
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
continue; continue;
}
phase = 7; phase = 7;
case 7: // sign case 7: // sign
if (c == '-' || c == '+') {ls = i; phase = 1; break;} if (c == '-' || c == '+') {
ls = i;
phase = 1;
break;
}
case 1: // search start case 1: // search start
if (c >= '0' && c <= '9') {le = i; if (ls < 0) ls = i; phase = 2; break;} if ((c >= '0' && c <= '9') || c == '.') {
if (c == '.') {le = i; if (ls < 0) ls = i; phase = 3; break;} le = i;
if (ls < 0) ls = i;
if (c == '.') phase = 3;
else phase = 2;
break;
}
phase = 9; phase = 9;
break; break;
case 2: // integer case 2: // integer
if (c == '.') {le = i; phase = 3; break;} if (c == '.') {
if (c == 'e' || c == 'E') {le = i; phase = 4; break;} le = i;
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') {le = i; break;} 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; phase = 6;
break; break;
case 3: // point case 3: // point
if (c == 'e' || c == 'E') {le = i; phase = 4; break;} if (c == 'e' || c == 'E') {
if (c >= '0' && c <= '9') {le = i; break;} le = i;
phase = 4;
break;
}
if (c >= '0' && c <= '9') {
le = i;
break;
}
phase = 6; phase = 6;
break; break;
case 4: // exp 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; phase = 6;
break; break;
case 5: // power case 5: // power
if (c >= '0' && c <= '9') {le = i; break;} if (c >= '0' && c <= '9') {
le = i;
break;
}
phase = 6; phase = 6;
break; break;
case 6: // suffix 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; phase = 9;
break; break;
} }
@@ -1035,22 +1218,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 PIString::takeRange(const PIChar start, const PIChar end, const PIChar shield) {
PIString ret; PIString ret;
bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end); bool trim_ = (start != ' ' && start != '\t' && start != '\n' && start != '\r'), eq = (start == end);
int sz = size_s(), ls = -1, le = -1, cnt = 0; int sz = size_s(), ls = -1, le = -1, cnt = 0;
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
PIChar c = at(i); PIChar c = at(i);
if (c == shield) {++i; continue;} if (c == shield) {
++i;
continue;
}
if (trim_) { if (trim_) {
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
continue; continue;
}
trim_ = false; trim_ = false;
} }
if (eq) { if (eq) {
if (c == start) { if (c == start) {
if (cnt == 0) ls = i; if (cnt == 0) {
else {le = i; cnt = 0; break;} ls = i;
} else {
le = i;
cnt = 0;
break;
}
cnt++; cnt++;
} }
} else { } else {
@@ -1073,6 +1277,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 { PIString PIString::inBrackets(const PIChar start, const PIChar end) const {
int slen = length(); int slen = length();
int st = -1, bcnt = 0; int st = -1, bcnt = 0;
@@ -1092,10 +1302,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 PIString::toUpperCase() const {
PIString str(*this); PIString str(*this);
int l = str.size(); 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; return str;
} }
@@ -1103,7 +1392,9 @@ PIString PIString::toUpperCase() const {
PIString PIString::toLowerCase() const { PIString PIString::toLowerCase() const {
PIString str(*this); PIString str(*this);
int l = str.size(); 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; return str;
} }
@@ -1142,25 +1433,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) { PIString & PIString::setReadableSize(llong bytes) {
clear(); 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.; double fres = bytes / 1024.;
llong res = bytes / 1024; llong res = bytes / 1024;
fres -= res; 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.; fres = res / 1024.;
res /= 1024; res /= 1024;
fres -= res; 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.; fres = res / 1024.;
res /= 1024; res /= 1024;
fres -= res; 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.; fres = res / 1024.;
res /= 1024; res /= 1024;
fres -= res; 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.; fres = res / 1024.;
res /= 1024; res /= 1024;
fres -= res; fres -= res;
@@ -1183,11 +1509,11 @@ void parseVersion(PIString s, PIVector<int> & codes, PIStringList & strs) {
int ind = s.findLast('.') + 1; int ind = s.findLast('.') + 1;
while (!_versionDelims_.contains(s[ind])) { while (!_versionDelims_.contains(s[ind])) {
++ind; ++ind;
if (ind > s.size_s() - 1) if (ind > s.size_s() - 1) break;
break;
} }
for (int i = 0; i < mccnt; ++i) for (int i = 0; i < mccnt; ++i) {
s.insert(ind, PIStringAscii(".0")); s.insert(ind, PIStringAscii(".0"));
}
} }
PIStringList comps; PIStringList comps;
while (!s.isEmpty()) { while (!s.isEmpty()) {
@@ -1201,8 +1527,7 @@ void parseVersion(PIString s, PIVector<int> & codes, PIStringList & strs) {
} }
} }
for (int i = 0; i < comps.size_s(); ++i) { for (int i = 0; i < comps.size_s(); ++i) {
if (comps[i].isEmpty()) if (comps[i].isEmpty()) comps[i] = '0';
comps[i] = '0';
bool ok = false; bool ok = false;
int val = comps[i].toInt(-1, &ok); int val = comps[i].toInt(-1, &ok);
if (ok) { if (ok) {
@@ -1236,6 +1561,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) { int versionCompare(const PIString & v0, const PIString & v1, int components) {
PIStringList strs[2]; PIVector<int> codes[2]; PIStringList strs[2]; PIVector<int> codes[2];
parseVersion(v0.toLowerCase(), codes[0], strs[0]); parseVersion(v0.toLowerCase(), codes[0], strs[0]);
@@ -1264,6 +1621,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) { PIString versionNormalize(const PIString & v) {
PIStringList strs; PIVector<int> codes; PIStringList strs; PIVector<int> codes;
parseVersion(v.toLowerCase(), codes, strs); parseVersion(v.toLowerCase(), codes, strs);
@@ -1286,10 +1662,7 @@ PIString versionNormalize(const PIString & v) {
PICout operator <<(PICout s, const PIString & v) { PICout operator <<(PICout s, const PIString & v) {
s.space(); s.space();
s.quote(); s.quote();
s.setControl(0, true); s.write(v);
s << v.data();
s.restoreControl();
s.quote(); s.quote();
return s; return s;
} }

View File

@@ -1,7 +1,8 @@
/*! @file pistring.h /*! \file pistring.h
* @brief String * \ingroup Core
* * \brief
* This file declare string and string list classes * \~english String class
* \~russian Класс строки
*/ */
/* /*
PIP - Platform Independent Primitives PIP - Platform Independent Primitives
@@ -26,712 +27,1533 @@
#define PISTRING_H #define PISTRING_H
#include "pibytearray.h" #include "pibytearray.h"
#include "piconstchars.h"
#define PIStringAscii PIString::fromAscii #define PIStringAscii PIString::fromAscii
class PIStringList; class PIStringList;
class PIP_EXPORT PIString: public PIDeque<PIChar> //! \ingroup Core
//! \~\brief
//! \~english String class.
//! \~russian Класс строки.
class PIP_EXPORT PIString
{ {
friend PIByteArray & operator >>(PIByteArray & s, PIString & v); friend PIByteArray & operator >>(PIByteArray & s, PIString & v);
friend PIByteArray & operator <<(PIByteArray & s, const PIString & v);
public: public:
//! Contructs an empty string typedef PIDeque<PIChar>::iterator iterator;
PIString(): PIDeque<PIChar>() {} 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 ; static const float ElideLeft ;
//! \~english Value for elide at center.
//! \~russian Значение для пропуска в середине.
static const float ElideCenter; static const float ElideCenter;
//! \~english Value for elide at right.
//! \~russian Значение для пропуска справа.
static const float ElideRight ; static const float ElideRight ;
PIString & operator +=(const PIChar c) {push_back(c); return *this;} PIString & operator +=(const PIChar & c) {d.push_back(c); return *this;}
PIString & operator +=(const char c) {push_back(PIChar(c)); return *this;} PIString & operator +=(const char c) {d.push_back(PIChar(c)); return *this;}
PIString & operator +=(const char * str); PIString & operator +=(const char * str);
PIString & operator +=(const wchar_t * 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 PIByteArray & ba) {appendFromChars((const char * )ba.data(), ba.size_s(), __utf8name__); return *this;}
PIString & operator +=(const PIString & str); 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;}
//! Contructs string with single symbol "c" //! \~english Contructs string with single character "c".
PIString(const PIChar c): PIDeque<PIChar>() {*this += c;} //! \~russian Создает строку из одного символа "c".
PIString(const char c): PIDeque<PIChar>() {*this += PIChar(c);} PIString(const char c) {*this += PIChar(c);}
/*! @brief Contructs string from c-string "str" //! \~english Contructs string from C-string "str" (system codepage).
* \details "str" should be null-terminated\n //! \~russian Создает строку из C-строки "str" (кодировка системы).
* Example: \snippet pistring.cpp PIString(char * ) */ //! \~\details
PIString(const char * str): PIDeque<PIChar>() {*this += str;} //! \~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 wchar_t c-string "str" //! \~english Contructs string from \c wchar_t C-string "str".
* \details "str" should be null-terminated\n //! \~russian Создает строку из \c wchar_t C-строки "str".
* Example: \snippet pistring.cpp PIString(wchar_t * ) */ //! \~\details
PIString(const wchar_t * str): PIDeque<PIChar>() {*this += str;} //! \~english
//! "str" should be null-terminated
//! \~russian
//! "str" должна заканчиваться нулевым \c wchar_t
//! \~\code
//! PIString s(L"string");
//! \endcode
PIString(const wchar_t * str) {*this += str;}
//! Contructs string from byte array "ba" //! \~english Contructs string from byte array "ba" (as UTF-8).
PIString(const PIByteArray & ba): PIDeque<PIChar>() {*this += ba;} //! \~russian Создает строку из байтового массива "ba" (как UTF-8).
PIString(const PIByteArray & ba) {*this += ba;}
//! @brief Contructs string from "len" characters of buffer "str" //! \~english Contructs string from "len" characters of buffer "str".
PIString(const PIChar * str, const int len): PIDeque<PIChar>(str, size_t(len)) {} //! \~russian Создает строку из "len" символов массива "str".
PIString(const PIChar * str, const int len): d(str, size_t(len)) {}
/*! @brief Contructs string from "len" characters of buffer "str" //! \~english Contructs string from "len" characters of buffer "str" (system codepage).
* \details Example: \snippet pistring.cpp PIString(char * , int) */ //! \~russian Создает строку из "len" символов массива "str" (кодировка системы).
PIString(const char * str, const int len): PIDeque<PIChar>() {appendFromChars(str, len);} //! \~\details
//! \~\code
//! PIString s("string", 3); // s = "str"
//! \endcode
PIString(const char * str, const int len) {appendFromChars(str, len);}
/*! @brief Contructs string as sequence of characters "c" of buffer with length "len" //! \~english Contructs string as sequence of characters "c" of buffer with length "len".
* \details Example: \snippet pistring.cpp PIString(int, char) */ //! \~russian Создает строку как последовательность длиной "len" символа "c".
PIString(const int len, const char c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(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));}
/*! @brief Contructs string as sequence of symbols "c" of buffer with length "len" //! \~english Contructs string as sequence of characters "c" of buffer with length "len".
* \details Example: \snippet pistring.cpp PIString(int, PIChar) */ //! \~russian Создает строку как последовательность длиной "len" символа "c".
PIString(const int len, const PIChar c): PIDeque<PIChar>() {for (int i = 0; i < len; ++i) push_back(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() {} PIString(const PIConstChars & c) {*this += c;}
~PIString();
PIString & operator =(const PIString & o) {if (this == &o) return *this; clear(); *this += o; return *this;} //! \~english Assign operator.
//! \~russian Оператор присваивания.
PIString & operator =(const PIString & o) {if (this == &o) return *this; d = o.d; return *this;}
PIString & operator =(PIString && o) {swap(o); return *this;} //! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
PIString & operator =(PIString && o) {d.swap(o.d); piSwap(data_, o.data_); return *this;}
//! Compare operator //! \~english Assign operator.
//! \~russian Оператор присваивания.
PIString & operator =(const PIConstChars & o) {d.clear(); *this += o; return *this;}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
PIString & operator =(const char * o) {d.clear(); *this += o; return *this;}
//! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator ==(const PIString & str) const; bool operator ==(const PIString & str) const;
//! Compare operator //! \~english Compare operator.
bool operator ==(const PIChar c) const {if (size_s() != 1) return false; return at(0) == c;} //! \~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);} bool operator ==(const char * str) const {return *this == PIString(str);}
//! Compare operator //! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator !=(const PIString & str) const; bool operator !=(const PIString & str) const;
//! Compare operator //! \~english Compare operator.
bool operator !=(const PIChar c) const {if (size_s() != 1) return true; return at(0) != c;} //! \~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);} bool operator !=(const char * str) const {return *this != PIString(str);}
//! Compare operator //! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <(const PIString & str) const; bool operator <(const PIString & str) const;
//! Compare operator //! \~english Compare operator.
bool operator <(const PIChar c) const {if (size_s() != 1) return size_s() < 1; return at(0) < c;} //! \~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);} bool operator <(const char * str) const {return *this < PIString(str);}
//! Compare operator //! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >(const PIString & str) const; bool operator >(const PIString & str) const;
//! Compare operator //! \~english Compare operator.
bool operator >(const PIChar c) const {if (size_s() != 1) return size_s() > 1; return at(0) > c;} //! \~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);} 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);} bool operator <=(const PIString & str) const {return !(*this > str);}
//! Compare operator //! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator <=(const PIChar c) const {return !(*this > c);} 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);} 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);} bool operator >=(const PIString & str) const {return !(*this < str);}
//! Compare operator //! \~english Compare operator.
//! \~russian Оператор сравнения.
bool operator >=(const PIChar c) const {return !(*this < c);} 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);} bool operator >=(const char * str) const {return *this >= PIString(str);}
/*! @brief Append string "str" at the end of string //! \~english Append string "str" at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(PIString) */ //! \~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;} PIString & operator <<(const PIString & str) {*this += str; return *this;}
/*! @brief Append symbol "c" at the end of string //! \~english Append character "c" at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(PIChar) */ //! \~russian Добавляет в конец символ "c".
PIString & operator <<(const PIChar c) {*this += c; return *this;} //! \~\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 //! \~english Append character `c` at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(PIChar) */ //! \~russian Добавляет в конец символ `c`.
PIString & operator <<(const char c) {*this += PIChar(c); return *this;} //! \~\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 //! \~english Append С-string "str" at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(char * ) */ //! \~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;} PIString & operator <<(const char * str) {*this += str; return *this;}
/*! @brief Append \c wchar_t c-string "str" at the end of string //! \~english Append \c wchar_t C-string "str" at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(wchar_t * ) */ //! \~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;} PIString & operator <<(const wchar_t * str) {*this += str; return *this;}
/*! @brief Append string representation of "num" at the end of string PIString & operator <<(const PIConstChars & str) {*this += str; return *this;}
* \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 int & num) {*this += PIString::fromNumber(num); return *this;} PIString & operator <<(const int & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const uint & 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 //! \~english Append string representation of "num" at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(int) */ //! \~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 long & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const ulong & 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 llong & num) {*this += PIString::fromNumber(num); return *this;}
PIString & operator <<(const ullong & 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 //! \~english Append string representation of "num" at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(int) */ //! \~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;} PIString & operator <<(const float & num) {*this += PIString::fromNumber(num); return *this;}
/*! @brief Append string representation of "num" at the end of string //! \~english Append string representation of "num" at the end of string.
* \details Example: \snippet pistring.cpp PIString::<<(int) */ //! \~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;} 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();}
//! @brief Insert string "str" at the begin of string //! \~english Iterator to the element following the last element.
PIString & prepend(const PIString & str) {insert(0, str); return *this;} //! \~russian Итератор на элемент, следующий за последним элементом.
//! \~\details
//! \~\return \ref stl_iterators
//! \~\sa \a begin(), \a rbegin(), \a rend()
inline iterator end() {return d.end();}
//! @brief Insert string "str" at the end of string inline const_iterator begin() const {return d.begin();}
PIString & append(const PIString & str) {*this += str; return *this;} 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;}
//! \~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" //! \~english Returns part of string from character at index "start" and maximum length "len".
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::mid //! \~russian Возвращает подстроку от символа "start" и максимальной длиной "len".
* \sa \a left(), \a right() */
PIString mid(const int start, const int len = -1) const; 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);} 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" //! \~english Returns part of string from start and maximum length "len".
* \details Example: \snippet pistring.cpp PIString::left //! \~russian Возвращает подстроку от начала и максимальной длиной "len".
* \sa \a mid(), \a right() */ //! \~\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);} PIString left(const int len) const {return len <= 0 ? PIString() : mid(0, len);}
/*! @brief Return part of string from right and maximum length "len" //! \~english Returns part of string at end and maximum length "len".
* \details Example: \snippet pistring.cpp PIString::right //! \~russian Возвращает подстроку максимальной длиной "len" и до конца.
* \sa \a mid(), \a left() */ //! \~\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);} 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" //! \~english Remove part of string from character as index "start" and maximum length "len" and return this string.
* and return this string //! \~russian Удаляет часть строки от символа "start" и максимальной длины "len", возвращает эту строку.
* \details All variants demonstrated in example: \snippet pistring.cpp PIString::cutMid
* \sa \a cutLeft(), \a cutRight() */
PIString & cutMid(const int start, const int len); PIString & cutMid(const int start, const int len);
/*! @brief Remove part of string from left and maximum length "len" and return this string //! \~english Remove part of string from start and maximum length "len" and return this string.
* \details Example: \snippet pistring.cpp PIString::cutLeft //! \~russian Удаляет часть строки от начала и максимальной длины "len", возвращает эту строку.
* \sa \a cutMid(), \a cutRight() */ //! \~\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);} 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 //! \~english Remove part of string at end and maximum length "len" and return this string.
* \details Example: \snippet pistring.cpp PIString::cutRight //! \~russian Удаляет часть строки максимальной длины "len" от конца, возвращает эту строку.
* \sa \a cutMid(), \a cutLeft() */ //! \~\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);} 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 //! \~english Remove spaces at the start and at the end of string and return this string.
* \details Example: \snippet pistring.cpp PIString::trim //! \~russian Удаляет пробельные символы с начала и конца строки и возвращает эту строку.
* \sa \a trimmed() */
PIString & trim(); PIString & trim();
/*! @brief Return copy of this string without spaces at the start and at the end //! \~english Returns copy of this string without spaces at the start and at the end.
* \details Example: \snippet pistring.cpp PIString::trimmed //! \~russian Возвращает копию этой строки без пробельных символов с начала и конца.
* \sa \a trim() */ //! \~\details
//! \~\code
//! PIString s(" \t string \n");
//! piCout << s.trimmed(); // s = "string"
//! piCout << s; // s = " string "
//! \endcode
//! \~\sa \a trim()
PIString trimmed() const; PIString trimmed() const;
/*! @brief Replace part of string from index "from" and maximum length "len" //! \~english Replace part of string from index "from" and maximum length "len" with string "with" and return this string.
* with string "with" and return this string //! \~russian Заменяет часть строки от символа "from" и максимальной длины "len" строкой "with", возвращает эту строку.
* \details Example: \snippet pistring.cpp PIString::replace_0
* \sa \a replaced(), \a replaceAll() */
PIString & replace(const int from, const int count, const PIString & 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" //! \~english Replace part copy of this string from index "from" and maximum length "len" with string "with".
* with string "with" and return copied string //! \~russian Заменяет часть копии этой строки от символа "from" и максимальной длины "len" строкой "with".
* \details Example: \snippet pistring.cpp PIString::replaced_0 //! \~\details
* \sa \a replace(), \a replaceAll() */ //! \~\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;} 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 //! \~english 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 //! \~russian Заменяет первую найденную подстроку "what" строкой "with", возвращает эту строку.
* Example: \snippet pistring.cpp PIString::replace_1
* \sa \a replaced(), \a replaceAll() */
PIString & replace(const PIString & what, const PIString & with, bool * ok = 0); PIString & replace(const PIString & what, const PIString & with, bool * ok = 0);
/*! @brief Replace first founded substring "what" with string "with" and return copied string //! \~english Replace in string copy first founded substring "what" with string "with".
* \details If "ok" is not null, it set to "true" if something was replaced\n //! \~russian Заменяет в копии строки первую найденную подстроку "what" строкой "with".
* Example: \snippet pistring.cpp PIString::replaced_1 //! \~\details
* \sa \a replaced(), \a replaceAll() */ //! \~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;} 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 //! \~english Replace all founded substrings "what" with strings "with" and return this string.
* \details Example: \snippet pistring.cpp PIString::replaceAll //! \~russian Заменяет все найденные подстроки "what" строками "with", возвращает эту строку.
* \sa \a replace(), \a replaced() */
PIString & replaceAll(const PIString & what, const PIString & with); PIString & replaceAll(const PIString & what, const PIString & with);
/*! @brief Replace all founded substrings "what" with symbol "with" and return this string //! \~english Replace all founded substrings "what" with characters "with" and return this string.
* \details Example: \snippet pistring.cpp PIString::replaceAll //! \~russian Заменяет все найденные подстроки "what" символами "with", возвращает эту строку.
* \sa \a replace(), \a replaced() */
PIString & replaceAll(const PIString & what, const char with); PIString & replaceAll(const PIString & what, const char with);
/*! @brief Replace all founded symbols "what" with symbol "with" and return this string //! \~english Replace all founded characters "what" with characters "with" and return this string.
* \details Example: \snippet pistring.cpp PIString::replaceAll //! \~russian Заменяет все найденные символы "what" символами "with", возвращает эту строку.
* \sa \a replace(), \a replaced() */
PIString & replaceAll(const char what, const char 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;} 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;} 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(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 //! \~english Repeat content of string "times" times and return this string.
* \details Example: \snippet pistring.cpp PIString::repeat */ //! \~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;} PIString & repeat(int times) {PIString ss(*this); times--; piForTimes (times) *this += ss; return *this;}
/*! @brief Returns repeated "times" times string //! \~english Returns repeated "times" times string.
* \details Example: \snippet pistring.cpp PIString::repeated */ //! \~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);} PIString repeated(int times) const {PIString ss(*this); return ss.repeat(times);}
/*! @brief Insert symbol "c" after index "index" and return this string //! \~english Insert character "c" after index "index" and return this string.
* \details Example: \snippet pistring.cpp PIString::insert_0 */ //! \~russian Вставляет символ "c" после позиции "index" и возвращает эту строку.
PIString & insert(const int index, const PIChar c) {PIDeque<PIChar>::insert(index, c); return *this;} //! \~\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 //! \~english Insert character "c" after index "index" and return this string.
* \details Example: \snippet pistring.cpp PIString::insert_1 */ //! \~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));} PIString & insert(const int index, const char c) {return insert(index, PIChar(c));}
/*! @brief Insert string "str" after index "index" and return this string //! \~english Insert string "str" after index "index" and return this string.
* \details Example: \snippet pistring.cpp PIString::insert_2 */ //! \~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); PIString & insert(const int index, const PIString & str);
/*! @brief Insert string "str" after index "index" and return this string //! \~english Insert string "str" after index "index" and return this string.
* \details Example: \snippet pistring.cpp PIString::insert_2 */ //! \~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));} PIString & insert(const int index, const char * c) {return insert(index, PIString(c));}
/*! @brief Enlarge string to length "len" by addition sequence of symbols //! \~english Enlarge string to length "len" by addition characters "c" at the end, and return this string.
* "c" at the end of string, and return this string //! \~russian Увеличивает длину строки до "len" добавлением символов "c" в конец и возвращает эту строку.
* \details Example: \snippet pistring.cpp PIString::expandRightTo //! \~\details
* \sa \a expandLeftTo() */ //! \~\code
PIString & expandRightTo(const int len, const PIChar c) {if (len > length()) resize(len, c); return *this;} //! 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 //! \~english Enlarge string to length "len" by addition characters "c" at the begin, and return this string.
* "c" at the beginning of string, and return this string //! \~russian Увеличивает длину строки до "len" добавлением символов "c" в начало и возвращает эту строку.
* \details Example: \snippet pistring.cpp PIString::expandLeftTo //! \~\details
* \sa \a expandRightTo() */ //! \~\code
PIString & expandLeftTo(const int len, const PIChar c) {if (len > length()) insert(0, PIString(len - length(), c)); return *this;} //! 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" //! \~english Enlarge copy of this string to length "len" by addition characters "c" at the end.
* by addition sequence of symbols "c" at the end of string //! \~russian Увеличивает длину копии этой строки до "len" добавлением символов "c" в конец.
* \sa \a expandRightTo() */ //! \~\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);} 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" //! \~english Enlarge copy of this string to length "len" by addition characters "c" at the begin.
* by addition sequence of symbols "c" at the beginning of string //! \~russian Увеличивает длину копии этой строки до "len" добавлением символов "c" в начало.
* \sa \a expandLeftTo() */ //! \~\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);} 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 //! \~english Add "c" characters at the beginning and end, and return this string.
* \sa \a quoted() */ //! \~russian Добавляет символ "c" в начало и конец и возвращает эту строку.
PIString & quote(PIChar c = PIChar('"')) {insert(0, c); *this += c; return *this;} //! \~\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 //! \~english Returns quoted copy of this string.
* \sa \a quote() */ //! \~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);} PIString quoted(PIChar c = PIChar('"')) {return PIString(*this).quote(c);}
/*! @brief Reverse string and return this string //! \~english Reverse string and return this string.
* \details Example: \snippet pistring.cpp PIString::reverse //! \~russian Разворачивает и возвращает эту строку.
* \sa \a reversed() */ //! \~\details
PIString & reverse() {PIString str(*this); clear(); piForeachCR (PIChar c, str) push_back(c); return *this;} //! \~\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 //! \~english Reverse copy of this string.
* \details Example: \snippet pistring.cpp PIString::reversed //! \~russian Разворачивает копию этой строки.
* \sa \a reverse() */ //! \~\details
PIString reversed() const {PIString str(*this); str.reverse(); return str;} //! \~\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 //! \~english Fit string to maximum size "size" by inserting ".." at position "pos" and return this string.
* \sa \a elided() */ //! \~russian Уменьшает строку до размера "size", вставляя ".." в положение "pos" и возвращает эту строку.
//! \~\sa \a elided()
PIString & elide(int size, float pos = ElideCenter); PIString & elide(int size, float pos = ElideCenter);
/*! @brief Elide copy of this string to maximum size \"size\" and return it //! \~english Fit copy of this string to maximum size "size" by inserting ".." at position "pos".
* \details Example: \snippet pistring.cpp PIString::elided //! \~russian Уменьшает копию этой строки до размера "size", вставляя ".." в положение "pos".
* \sa \a elide() */ //! \~\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;} 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 //! \~english Take a part of string from character at index "start" and maximum length "len" and return it.
* \sa \a takeLeft, \a takeRight() */ //! \~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;} 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 //! \~english Take a part from the begin of string with maximum length "len" and return it.
* \sa \a takeMid(), \a takeRight() */ //! \~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;} 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 //! \~english Take a part from the end of string with maximum length "len" and return it.
* \sa \a takeMid(), \a takeLeft() */ //! \~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;} 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 //! \~english Take a character from the begin of this string and return it.
* \details Example: \snippet pistring.cpp PIString::takeSymbol //! \~russian Извлекает символ с начала строки и возвращает его как строку.
* \sa \a takeWord(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
PIString takeSymbol(); PIString takeSymbol();
/*! @brief Take a word from the begin of this string and return it //! \~english Take a word from the begin of this string and return it.
* \details Example: \snippet pistring.cpp PIString::takeWord //! \~russian Извлекает слово с начала строки и возвращает его.
* \sa \a takeSymbol(), \a takeCWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
PIString takeWord(); PIString takeWord();
/*! @brief Take a word with letters, numbers and '_' symbols from the //! \~english Take a word with letters, numbers and '_' characters from the begin of this string and return it.
* begin of this string and return it //! \~russian Извлекает слово из букв, цифр и симолов '_' с начала строки и возвращает его.
* \details Example: \snippet pistring.cpp PIString::takeCWord
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber(), \a takeRange() */
PIString takeCWord(); PIString takeCWord();
/*! @brief Take a line from the begin of this string and return it //! \~english Take a line from the begin of this string and return it.
* \details Example: \snippet pistring.cpp PIString::takeLine //! \~russian Извлекает строку текста (до новой строки) с начала строки и возвращает её.
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeNumber(), \a takeRange() */
PIString takeLine(); PIString takeLine();
/*! @brief Take a number with C-format from the begin of this string and return it //! \~english Take a number with C-format from the begin of this string and return it.
* \details Example: \snippet pistring.cpp PIString::takeNumber //! \~russian Извлекает число в C-формате с начала строки и возвращает его как строку.
* \sa \a takeSymbol(), \a takeWord(), \a takeCWord(), \a takeLine(), \a takeRange() */
PIString takeNumber(); PIString takeNumber();
/*! @brief Take a range between "start" and "end" symbols from the begin of this //! \~english Take a range between "start" and "end" characters from the begin of this string and return it.
* string and return it. //! \~russian Извлекает диапазон между символами "start" и "end" с начала строки и возвращает его.
* \details "Shield" symbol prevent analysis of the next symbol.
* Example: \snippet pistring.cpp PIString::takeRange
* \sa \a takeSymbol(), \a takeWord(), \a takeLine(), \a takeNumber() */
PIString takeRange(const PIChar start, const PIChar end, const PIChar shield = '\\'); 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 //! \~english Returns string in brackets "start" and "end" characters from the beginning.
* string and return it. //! \~russian Возвращает строку между символами "start" и "end" с начала строки.
* \details Example: string = "a(b(c)d)e"; inBrackets('(', ')') = "b(c)d"; */
PIString inBrackets(const PIChar start, const PIChar end) const; PIString inBrackets(const PIChar start, const PIChar end) const;
/*! @brief Return real bytes count of this string //! \~english Returns \c char * representation of this string in system codepage.
* \details It`s equivalent length of char sequence //! \~russian Возвращает \c char * представление строки в системной кодировке.
* returned by function \a data() - 1, without terminating null-char \n const char * data() const;
* Example: \snippet pistring.cpp PIString::lengthAscii
* \sa \a data() */
int lengthAscii() const {buildData(__syslocname__); return data_.size_s() - 1;}
/*! @brief Return \c char * representation of this string in system codepage //! \~english Returns \c char * representation of this string in terminal codepage.
* \details This function fill buffer by sequence //! \~russian Возвращает \c char * представление строки в кодировке консоли.
* 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() */
const char * dataConsole() const; const char * dataConsole() const;
/*! @brief Return \c char * representation of this string in UTF-8 //! \~english Returns \c char * representation of this string in UTF-8.
* \details This function fill buffer by sequence //! \~russian Возвращает \c char * представление строки в кодировке UTF-8.
* 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() */
const char * dataUTF8() const; const char * dataUTF8() const;
/*! @brief Return \c char * representation of this string in ASCII //! \~english Returns \c char * representation of this string in ASCII.
* \details This function fill buffer by sequence //! \~russian Возвращает \c char * представление строки в кодировке ASCII.
* of chars. Minimum length of this buffer is count
* of symbols. Returned \c char * is valid until next
* execution of this function.\n */
const char * dataAscii() const; const char * dataAscii() const;
//! Returns hash //! \~english Returns hash of string
//! \~russian Возвращает хэш строки
uint hash() const; uint hash() const;
//! @brief Return \a PIByteArray contains \a data() of this string without terminating null-char //! \~english Same as \a toUTF8().
PIByteArray toByteArray() const {buildData(__utf8name__); return data_.resized(data_.size_s() - 1);} //! \~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; 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; PIByteArray toCharset(const char * c) const;
/*! @brief Split string with delimiter "delim" to \a PIStringList and return it //! \~english Split string with delimiter "delim" to \a PIStringList.
* \details Example: \snippet pistring.cpp PIString::split */ //! \~russian Разделяет строку в \a PIStringList через разделитель "delim".
//! \~\details
//! \~\code
//! PIString s("1 2 3");
//! piCout << s.split(" "); // {"1", "2", "3"}
//! \endcode
PIStringList split(const PIString & delim) const; 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; 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; PIString toLowerCase() const;
// TODO: doxygen
PIString toNativeDecimalPoints() const; PIString toNativeDecimalPoints() const;
//! @brief Returns if string contains "c" //! \~english Returns if string contains character "c".
bool contains(const char c) const {return PIDeque<PIChar>::contains(PIChar(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));} 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;} bool contains(const PIString & str) const {return find(str) >= 0;}
//! @brief Search symbol "c" from symbol at index "start" and return first occur position //! \~english Search character "c" from character at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::find //! \~russian Ищет символ "c" от символа "start" и возвращает первое вхождение.
int find(const char c, const int start = 0) const; int find(const char c, const int start = 0) const;
//! @brief Search substring "str" from symbol at index "start" and return first occur position //! \~english Search character "c" from character at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::find //! \~russian Ищет символ "c" от символа "start" и возвращает первое вхождение.
int find(PIChar c, const int start = 0) const {return d.indexOf(c, start);}
//! \~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; int find(const PIString & str, const int start = 0) const;
//! @brief Search substring "str" from symbol at index "start" and return first occur position //! \~english Search substring "str" from character at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::find //! \~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);} 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 //! \~english Search any character of "str" from character at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findLast //! \~russian Ищет любой символ строки "str" от симола "start" и возвращает первое вхождение.
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
int findAny(const PIString & str, const int start = 0) const; 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 //! \~english Search any character of "str" from character at index "start" and return first occur position.
//! \details Example: \snippet pistring.cpp PIString::findAny //! \~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);} int findAny(const char * str, const int start = 0) const {return findAny(PIString(str), start);}
//! @brief Search any symbol of "str" from symbol at index "start" and return last occur position //! \~english Search character "c" from character at index "start" and return last occur position.
//! \details Example: \snippet pistring.cpp PIString::findAnyLast //! \~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;
//! \~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; 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 //! \~english Search any character of "str" from character at index "start" and return last occur position.
//! \details Example: \snippet pistring.cpp PIString::findAnyLast //! \~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);} 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; 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));} 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; 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; bool endsWith(const PIString & str) const;
//! @brief Return symbols length of string //! \~english Returns characters length of string.
int length() const {return size();} //! \~russian Возвращает длину строки в символах.
int length() const {return d.size_s();}
//! @brief Return \c true if string is empty, i.e. length = 0 //! \~english Returns characters length of string.
bool isEmpty() const {return (size() == 0 || *this == "");} //! \~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; 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; char toChar() const;
//! @brief Return \c short numeric value of string in base "base" //! \~english Returns \c short numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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));} 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" //! \~english Returns \c ushort numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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));} 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" //! \~english Returns \c int numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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));} 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" //! \~english Returns \c uint numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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));} 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" //! \~english Returns \c long numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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));} 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" //! \~english Returns \c ulong numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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));} 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" //! \~english Returns \c llong numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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);} 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" //! \~english Returns \c ullong numeric value of string in base "base".
//! \details Example: \snippet pistring.cpp PIString::toNumber //! \~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));} ullong toULLong(int base = -1, bool * ok = 0) const {return ullong(toNumberBase(*this, base, ok));}
//! @brief Return \c float numeric value of string //! \~english Returns \c float numeric value of string.
//! \details Example: \snippet pistring.cpp PIString::toFloat //! \~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; float toFloat() const;
//! @brief Return \c double numeric value of string //! \~english Returns \c double numeric value of string.
//! \details Example: \snippet pistring.cpp PIString::toFloat //! \~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; double toDouble() const;
//! @brief Return \c ldouble numeric value of string //! \~english Returns \c ldouble numeric value of string.
//! \details Example: \snippet pistring.cpp PIString::toFloat //! \~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; ldouble toLDouble() const;
//! @brief Set string content to numeric representation of "value" in base "base" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const short value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const ushort value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const int value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const uint value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const long value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const ulong value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const llong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" in base "base" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setNumber //! \~russian Устанавливает содержимое строки в текстовое представление "value" по основанию "base" и возвращает эту строку.
PIString & setNumber(const ullong & value, int base = 10, bool * ok = 0) {clear(); *this += PIString::fromNumber(value, base, ok); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" with format "format" and precision "precision" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setFloat //! \~russian Устанавливает содержимое строки в текстовое представление "value" в формате "format" и точностью "precision" и возвращает эту строку.
PIString & setNumber(const float value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" with format "format" and precision "precision" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setFloat //! \~russian Устанавливает содержимое строки в текстовое представление "value" в формате "format" и точностью "precision" и возвращает эту строку.
PIString & setNumber(const double & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;} //! \~\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" //! \~english Set string content to text representation of "value" with format "format" and precision "precision" and return this string.
//! \details Example: \snippet pistring.cpp PIString::setFloat //! \~russian Устанавливает содержимое строки в текстовое представление "value" в формате "format" и точностью "precision" и возвращает эту строку.
PIString & setNumber(const ldouble & value, char format = 'f', int precision = 8) {clear(); *this += PIString::fromNumber(value, format, precision); return *this;} //! \~\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 //! \~english Set string content to human readable size in B/kB/MB/GB/TB/PB.
//! \details Example: \snippet pistring.cpp PIString::setReadableSize //! \~russian Устанавливает содержимое в строку с читаемым размером B/kB/MB/GB/TB/PB.
//! \~\sa PIString::readableSize()
PIString & setReadableSize(llong bytes); PIString & setReadableSize(llong bytes);
//! @brief Return string contains numeric representation of "value" in base "base" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" in base "base".
//! \details Example: \snippet pistring.cpp PIString::fromNumber //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" with format "format" and precision "precision".
//! \details Example: \snippet pistring.cpp PIString::fromFloat //! \~russian Возвращает строковое представление числа "value" в формате "format" и точностью "precision".
static PIString fromNumber(const float value, char format = 'f', int precision = 8) {return ftos(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" //! \~english Returns string contains numeric representation of "value" with format "format" and precision "precision".
//! \details Example: \snippet pistring.cpp PIString::fromFloat //! \~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);} 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" //! \~english Returns string contains numeric representation of "value" with format "format" and precision "precision".
//! \details Example: \snippet pistring.cpp PIString::fromFloat //! \~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);} static PIString fromNumber(const ldouble & value, char format = 'f', int precision = 8) {return dtos(value, format, precision);}
//! @brief Return "true" or "false" //! \~english Returns "true" or "false"
static PIString fromBool(const bool value) {return PIString(value ? "true" : "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); 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); 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); static PIString fromUTF8(const char * s);
//! @brief Return string constructed from UTF-8 //! \~english Returns string constructed from UTF-8.
static PIString fromUTF8(const PIByteArray &ba); //! \~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); 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); static PIString fromAscii(const char * s, int len);
//! @brief Return string constructed from "c" codepage //! \~english Returns string constructed from "cp" codepage.
static PIString fromCodepage(const char * s, const char * c); //! \~russian Возвращает строку созданную из кодировки "cp".
static PIString fromCodepage(const char * s, const char * cp);
//! @brief Return string contains human readable size in B/kB/MB/GB/TB //! \~english Returns string contains human readable size in B/kB/MB/GB/TB/PB.
//! \details Example: \snippet pistring.cpp PIString::readableSize //! \~russian Возвращает строку с читаемым размером B/kB/MB/GB/TB/PB.
//! \~\sa PIString::setReadableSize()
static PIString readableSize(llong bytes); 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: private:
static const char toBaseN[]; static const char toBaseN[];
static const int fromBaseN[]; static const char fromBaseN[];
static PIString itos(const int num); static PIString itos(const int num);
static PIString ltos(const long num); static PIString ltos(const long num);
@@ -739,52 +1561,72 @@ private:
static PIString uitos(const uint num); static PIString uitos(const uint num);
static PIString ultos(const ulong num); static PIString ultos(const ulong num);
static PIString ulltos(const ullong 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 dtos(const double num, char format = 'f', int precision = 8);
static PIString fromNumberBaseS(const llong value, int base = 10, bool * ok = 0); 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 PIString fromNumberBaseU(const ullong value, int base = 10, bool * ok = 0);
static llong toNumberBase(const PIString & value, int base = -1, 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 appendFromChars(const char * c, int s, const char * cp = __syslocname__);
void buildData(const char * cp = __syslocname__) const; void buildData(const char * cp = __syslocname__) const;
void deleteData() const;
void trimsubstr(int &st, int &fn) 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); 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 //! \relatesalso PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PIString & v) {s << *(PIDeque<PIChar>*)&v; return s;} //! \~english Restore operator.
//! \~russian Оператор извлечения.
//! \relatesalso PIByteArray @brief Input operator from PIByteArray inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {v.d.clear(); s >> v.d; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIString & v) {v.clear(); s >> *(PIDeque<PIChar>*)&v; 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;} 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;} 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;} 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;} 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);} 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); 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); PIString PIP_EXPORT versionNormalize(const PIString & v);
template<> inline uint piHash(const PIString & s) {return s.hash();} 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 #endif // PISTRING_H

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