Compare commits
320 Commits
zmq
...
8551499a5e
| Author | SHA1 | Date | |
|---|---|---|---|
| 8551499a5e | |||
|
|
1eaecb288f | ||
|
|
170a713357 | ||
| 54cc6c55b2 | |||
| e6aa3c34d4 | |||
| bb40f69298 | |||
| af9a9e78b9 | |||
| af1264e42b | |||
| eb91fbfc45 | |||
| 4ea5465637 | |||
| ab7769dd5a | |||
| b1e220e454 | |||
| 1b499530c5 | |||
| b0d48caaad | |||
|
|
d6758a8562 | ||
| 97734953dd | |||
| bd98583116 | |||
|
|
ddba8f401b | ||
|
|
4725eb96d6 | ||
|
|
38fd1b5dc4 | ||
| 16c12a2756 | |||
|
|
1b09ad5c27 | ||
|
|
00d06f71ba | ||
|
|
3873f0b03b | ||
| 6ae6e9a540 | |||
|
|
bbc83128b0 | ||
|
|
d13e68c206 | ||
| a4882dc054 | |||
|
|
a1b9b7e1d6 | ||
|
|
e1b89aeca8 | ||
| 242abaaf59 | |||
|
|
0116387fe3 | ||
|
|
f5953a0ba7 | ||
|
|
7aa407264f | ||
|
|
59c7896577 | ||
|
|
a69de63db0 | ||
| e96b399da7 | |||
| 33eefd7453 | |||
| c7fffe1280 | |||
| 1b04d7ecce | |||
| b66272a68a | |||
| 12c032392c | |||
| ffa25c18f0 | |||
| f67e3030b9 | |||
| 1028233553 | |||
| ef8ffcd02f | |||
| 0897a8369f | |||
| fa19ad1093 | |||
| 8c6b3613b6 | |||
| a23eb341e2 | |||
| b2bc385397 | |||
| 0f9e592273 | |||
| cf4f58ed95 | |||
| 0243f588bc | |||
| af77974e91 | |||
| a502182eba | |||
| d219baee27 | |||
| 0ea1e2c856 | |||
| 3107949e6f | |||
| 460519c075 | |||
| 9347ed2e55 | |||
| 5770adfd34 | |||
| 9714d8ea42 | |||
| 0b3ee4bb6a | |||
| d1f7065c8a | |||
| 6995c25613 | |||
| 28ce6e8f3f | |||
| 8d5730f715 | |||
| 2bbdbc3ac9 | |||
| 19e4eee222 | |||
| 4139d88103 | |||
| 6881fd13b7 | |||
|
|
8c8553a6af | ||
| 97dd19f0c7 | |||
|
|
784c949b1a | ||
|
|
7325e12e30 | ||
| 019ddbb80b | |||
|
|
6322b248a8 | ||
| c1c47b4869 | |||
| 2f4e73ef13 | |||
| 5ae1cfae87 | |||
| 5d82caf889 | |||
| d3028a3ce8 | |||
| eef4573a68 | |||
| 48f3b62540 | |||
|
|
f7d6302572 | ||
|
|
7ad520a1c3 | ||
|
|
4bc12989ca | ||
|
|
186c71d973 | ||
|
|
06c8e6af10 | ||
|
|
69b9589e84 | ||
|
|
5c767c5e3e | ||
|
|
9cd0389a0b | ||
|
|
a7ffc85404 | ||
|
|
2e9c3a1dbf | ||
| 9f581335d3 | |||
| e70e1c0203 | |||
| cb179de856 | |||
| 0aaa5ba890 | |||
| 0cf7fb9f25 | |||
| a304997177 | |||
| d6ba51e4bc | |||
| 892edb7d5b | |||
| c3cf0f3586 | |||
| 2dec17e871 | |||
| 88ffd602d6 | |||
| a57e51bdf8 | |||
| 44c52c40f1 | |||
| 6ecd04b0d8 | |||
| 964823b332 | |||
| ca8839f097 | |||
| 546ad6a744 | |||
| bd9ad16074 | |||
| 23907c7043 | |||
| a6cea11911 | |||
| cea7a7c121 | |||
| 095ecd254f | |||
| 2246b8b5fd | |||
| 914ff5355d | |||
| 858269a46b | |||
| 5072d8c915 | |||
| 5f8c04a78e | |||
| 41fb7cc40d | |||
| 6a399c7d39 | |||
| 90afc369f0 | |||
|
|
765ef7368e | ||
| 03384d02a0 | |||
| cf48c9ebf7 | |||
| dd3d42944e | |||
| c2e44dc3ba | |||
| c1c324a5a8 | |||
| 7f93ba55b4 | |||
| fcd871c0fc | |||
| 0c54709414 | |||
| 7a458c5cbe | |||
| 8da0469dbf | |||
| 38b75c85d7 | |||
| 833d0333d7 | |||
| e67a426ff2 | |||
| 39e4d9a73c | |||
|
|
91216c4b17 | ||
|
|
416b142889 | ||
|
|
cb4df7dc42 | ||
|
|
99a4546775 | ||
|
|
8a9864a91c | ||
| 6485d81025 | |||
|
|
db54d0b052 | ||
|
|
87105cff21 | ||
|
|
a489daa475 | ||
| c476a06e8c | |||
| 9deae168a6 | |||
|
|
93b881da1b | ||
|
|
8beaac5193 | ||
|
|
d4294e3d95 | ||
|
|
8c6db321cf | ||
|
|
35e68bcd0e | ||
|
|
f01ca5e5bf | ||
| bef0ac1194 | |||
| 9fa78a1dbf | |||
| 4b32101de6 | |||
|
|
6abec38856 | ||
|
|
d22af96bea | ||
| 7b65a59a6e | |||
| 42e253adc7 | |||
|
|
bb45a60d94 | ||
|
|
fa93c8a486 | ||
| 77e0423375 | |||
| c7e67b309e | |||
|
|
2ab2614ab4 | ||
|
|
5ed900c46c | ||
|
|
fb104a9f24 | ||
|
|
42bfe7c587 | ||
| 4f2218619c | |||
|
|
e4e16764f3 | ||
| 00830958df | |||
|
|
486fdf3dcd | ||
|
|
7cd824f3ab | ||
|
|
60c9d60079 | ||
| 397d273802 | |||
| a117844233 | |||
| d5c27b1181 | |||
| c90d06871e | |||
| fb282d405d | |||
|
|
f83d08cf56 | ||
|
|
0194e3f6b6 | ||
|
|
1edd9e4c55 | ||
|
|
aa417be1d3 | ||
|
|
7ab16b641d | ||
|
|
42fd417e34 | ||
|
|
c2ceb710c5 | ||
|
|
288062cfd6 | ||
|
|
9f1ae76d1e | ||
| 7c927da979 | |||
|
|
7a9c3f72ca | ||
| 35d340aaab | |||
| 5d98a7dd3a | |||
| 5393225538 | |||
| 831f202536 | |||
| 81b749caa2 | |||
| a50953ae7c | |||
| 08c5d15e6a | |||
| ff70bf6a0e | |||
| a315f7af25 | |||
|
|
4c7df57e66 | ||
|
|
7dee8f6313 | ||
|
|
0ad6ca6602 | ||
|
|
649850a1ba | ||
|
|
8bb1af8d2a | ||
| 7a0adf5e28 | |||
|
|
6241795b60 | ||
|
|
9d0451455a | ||
|
|
9a8b9c7141 | ||
| 866f71edb5 | |||
|
|
4bae04feec | ||
|
|
415160387b | ||
|
|
3dd0d0b6cf | ||
|
|
2596b119ac | ||
| 20e0771331 | |||
| 7a26ae7292 | |||
| cc4e1f48aa | |||
|
|
6e6305d2ec | ||
|
|
3e9cb2481c | ||
|
|
ea624f1223 | ||
|
|
e4aec3f95e | ||
| 7d83c6fe19 | |||
| 7ef4321a3d | |||
| 54b5372356 | |||
|
|
9bf1a11701 | ||
|
|
99280a40ef | ||
|
|
99061f6e24 | ||
|
|
2fd139b1e3 | ||
| ae29b4514c | |||
| 58de1ceafc | |||
| 20e6d1be99 | |||
| 2a877fbb6b | |||
| 2a6ebc9d8d | |||
|
|
c3c98b9d78 | ||
|
|
443e8b46a6 | ||
|
|
fff2aa468a | ||
| 1918e55a97 | |||
| eb6d378de2 | |||
| b1b174ba64 | |||
|
|
4921a3b0fd | ||
|
|
8296e9a32b | ||
|
|
7403ee67be | ||
|
|
cde2341c1f | ||
|
|
542f180d9d | ||
| 86130d7105 | |||
|
|
c9e329d27d | ||
|
|
d4c6c410da | ||
|
|
a7df53fbfe | ||
|
|
0504fa187e | ||
| 1d9a39f792 | |||
| cbdaabee4a | |||
| 3c8ccf357b | |||
|
|
92b20f6f46 | ||
| 04d7ed77d9 | |||
| a2a205cfd2 | |||
| d3b6597042 | |||
|
|
48c885e12a | ||
|
|
6e5a5a6ade | ||
| 21e03fc8cb | |||
| b85de0d704 | |||
|
|
f781cc3846 | ||
|
|
1cb3d4ffe9 | ||
|
|
9293706634 | ||
|
|
fde6bdf17f | ||
|
|
a1c1fd8339 | ||
|
|
01b39dc75f | ||
| 07ec32c969 | |||
| 042366e19e | |||
| 948a90fcd9 | |||
| c404688bbd | |||
| aa76a15f40 | |||
|
|
ca20785b53 | ||
|
|
13d0b2f960 | ||
|
|
46571ac39f | ||
| 36d770ea2e | |||
|
|
bc7d129a9e | ||
| 8accc28804 | |||
|
|
62e130f91b | ||
| a009221092 | |||
| dedc35b466 | |||
| 5e33587703 | |||
| 950f6830da | |||
|
|
19a8ca84e6 | ||
|
|
ece3fb1536 | ||
| 0d119502a8 | |||
| cc5951cfc3 | |||
| 61d42e0ac5 | |||
| 127935086c | |||
| 76ed60edf3 | |||
| 3b0a1c70fe | |||
| 186e07e45d | |||
| 047cff7d6e | |||
| 305275e3ac | |||
| efb0d5f4f9 | |||
| 991a074538 | |||
| f82b6c12ee | |||
| 00edfa4ef0 | |||
| 35a3ce6402 | |||
| be3ce454a0 | |||
| 4c85206cfa | |||
| 5ecdcbe46e | |||
| c937d7251a | |||
| 1cc46468c1 | |||
| 5cc8ef1eb0 | |||
| 99e135caa2 | |||
| 9de7045d63 | |||
| 0e65151e9f | |||
| 3c20728210 | |||
| 4c0530d89a | |||
| f5af8a1da9 | |||
| 44b9c37391 | |||
| 97b0b6fc0c | |||
| 1a2e9afaef | |||
| 39a3a23a24 | |||
| ee131921a0 | |||
| f8818c8537 | |||
| b07242226e |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,4 +2,5 @@
|
|||||||
/.svn
|
/.svn
|
||||||
/doc/rtf
|
/doc/rtf
|
||||||
_unsused
|
_unsused
|
||||||
CMakeLists.txt.user*
|
CMakeLists.txt.user*
|
||||||
|
/include
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lapi_c
|
#define lapi_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lcode_c
|
#define lcode_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lctype_c
|
#define lctype_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define ldebug_c
|
#define ldebug_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define ldo_c
|
#define ldo_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define ldump_c
|
#define ldump_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lfunc_c
|
#define lfunc_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lgc_c
|
#define lgc_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define llex_c
|
#define llex_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lmem_c
|
#define lmem_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lobject_c
|
#define lobject_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lopcodes_c
|
#define lopcodes_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lparser_c
|
#define lparser_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lstate_c
|
#define lstate_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lstring_c
|
#define lstring_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define ltable_c
|
#define ltable_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define ltm_c
|
#define ltm_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lundump_c
|
#define lundump_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lvm_c
|
#define lvm_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define lzio_c
|
#define lzio_c
|
||||||
#define LUA_CORE
|
|
||||||
|
|
||||||
#include "lprefix.h"
|
#include "lprefix.h"
|
||||||
|
|
||||||
|
|||||||
@@ -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 99)
|
||||||
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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -20,12 +20,7 @@ main library
|
|||||||
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
|
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
|
||||||
include(SHSTKMacros)
|
include(SHSTKMacros)
|
||||||
|
|
||||||
shstk_set_find_dirs(pip)
|
shstk_set_find_dirs(pip PIP)
|
||||||
if(PIP_DIR)
|
|
||||||
list(APPEND pip_LIBDIR "${PIP_DIR}/lib")
|
|
||||||
list(APPEND pip_INCDIR "${PIP_DIR}/include/pip")
|
|
||||||
list(APPEND pip_BINDIR "${PIP_DIR}/bin")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
|
set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
|
||||||
|
|
||||||
@@ -71,6 +66,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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
355
doc/Doxyfile.in
355
doc/Doxyfile.in
@@ -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
|
||||||
@@ -2230,13 +2282,7 @@ EXTERNAL_GROUPS = YES
|
|||||||
# be listed.
|
# be listed.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
EXTERNAL_PAGES = YES
|
EXTERNAL_PAGES = NO
|
||||||
|
|
||||||
# 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
|
||||||
|
|||||||
@@ -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 _() {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
inline PICout operator <<(PICout s, const PIByteArray & ba) {
|
inline PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||||
s.space(); // insert space after previous output
|
s.space(); // insert space after previous output
|
||||||
s.quote(); // ONLY if you want to quoted your type
|
s.quote(); // ONLY if you want to quoted your type
|
||||||
s.setControl(0, true); // clear all features and
|
s.saveAndSetControls(0); // clear all features and
|
||||||
// save them to stack,
|
// save them to stack,
|
||||||
// now it`s behavior similar to std::cout
|
// now it`s behavior similar to std::cout
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ inline PICout operator <<(PICout s, const PIByteArray & ba) {
|
|||||||
for (uint i = 0; i < ba.size(); ++i)
|
for (uint i = 0; i < ba.size(); ++i)
|
||||||
s << ba[i];
|
s << ba[i];
|
||||||
|
|
||||||
s.restoreControl(); // restore features from stack
|
s.restoreControls(); // restore features from stack
|
||||||
s.quote(); // ONLY if you want to quoted your type
|
s.quote(); // ONLY if you want to quoted your type
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,25 +3,24 @@ void _() {
|
|||||||
|
|
||||||
//! [0]
|
//! [0]
|
||||||
class SomeIO: public PIIODevice {
|
class SomeIO: public PIIODevice {
|
||||||
PIIODEVICE(SomeIO)
|
PIIODEVICE(SomeIO, "myio")
|
||||||
public:
|
public:
|
||||||
SomeIO(): PIIODevice() {}
|
SomeIO(): PIIODevice() {}
|
||||||
protected:
|
protected:
|
||||||
bool openDevice() {
|
bool openDevice() override {
|
||||||
// open your device here
|
// open your device here
|
||||||
return if_success;
|
return if_success;
|
||||||
}
|
}
|
||||||
int read(void * read_to, int max_size) {
|
ssize_t readDevice(void * read_to, ssize_t max_size) override {
|
||||||
// read from your device here
|
// read from your device here
|
||||||
return readed_bytes;
|
return readed_bytes;
|
||||||
}
|
}
|
||||||
int write(const void * data, int max_size) {
|
ssize_t writeDevice(const void * data, ssize_t max_size) override {
|
||||||
// write to your device here
|
// write to your device here
|
||||||
return written_bytes;
|
return written_bytes;
|
||||||
}
|
}
|
||||||
PIString fullPathPrefix() const {return "myio";}
|
void configureFromFullPathDevice(const PIString & full_path) override {
|
||||||
void configureFromFullPath(const PIString & full_path) {
|
// parse full_path and configure device here
|
||||||
// parse full_path and configure device there
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
REGISTER_DEVICE(SomeIO)
|
REGISTER_DEVICE(SomeIO)
|
||||||
@@ -39,7 +38,7 @@ ser.configure("example.conf", "dev");
|
|||||||
//! [configureDevice]
|
//! [configureDevice]
|
||||||
class SomeIO: public PIIODevice {
|
class SomeIO: public PIIODevice {
|
||||||
...
|
...
|
||||||
bool configureDevice(const void * e_main, const void * e_parent) {
|
bool configureDevice(const void * e_main, const void * e_parent) override {
|
||||||
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
|
PIConfig::Entry * em = (PIConfig::Entry * )e_main;
|
||||||
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
PIConfig::Entry * ep = (PIConfig::Entry * )e_parent;
|
||||||
setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep));
|
setStringParam(readDeviceSetting<PIString>("stringParam", stringParam(), em, ep));
|
||||||
|
|||||||
@@ -2,8 +2,5 @@
|
|||||||
|
|
||||||
void _() {
|
void _() {
|
||||||
//! [main]
|
//! [main]
|
||||||
mutex.lock();
|
|
||||||
// ... your code here
|
|
||||||
mutex.unlock();
|
|
||||||
//! [main]
|
//! [main]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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
BIN
doc/images/pirect.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
BIN
doc/images/pivector_begin.png
Normal file
BIN
doc/images/pivector_begin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
doc/images/pivector_rbegin.png
Normal file
BIN
doc/images/pivector_rbegin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
297
doc/pages/code_model.md
Normal file
297
doc/pages/code_model.md
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
\~english \page code_model Code generation
|
||||||
|
\~russian \page code_model Генерация кода
|
||||||
|
|
||||||
|
\~english
|
||||||
|
|
||||||
|
\~russian
|
||||||
|
|
||||||
|
# Введение
|
||||||
|
|
||||||
|
Кодогенерация помогает в случаях, когда нужен доступ к строковому представлению
|
||||||
|
сущностей (классов, перечислений, ...), либо автоматизированная де/сериализация
|
||||||
|
структур и классов.
|
||||||
|
|
||||||
|
Например, необходимо для создания интерфейса получить в готовом виде список
|
||||||
|
пар "имя" = "значение" от какого-либо перечисления, либо обойти список
|
||||||
|
вложенных в класс структур с дополнительными метками. Или просто описать
|
||||||
|
структуру любой сложности, пометить поля номерами и получить готовые операторы
|
||||||
|
де/сериализации для PIBinaryStream с возможностью будущих изменений и сохранением
|
||||||
|
обратной совместимости.
|
||||||
|
|
||||||
|
# pip_cmg
|
||||||
|
|
||||||
|
PIP предоставляет утилиту, которая берет на вход файлы исходного кода, пути
|
||||||
|
включения, параметры и макросы, и на выходе создает h/cpp пару файлов с
|
||||||
|
необходимым функционалом. В зависимости от параметров, в этих файлах будут
|
||||||
|
присутствовать секции:
|
||||||
|
* метаинформации о сущностях;
|
||||||
|
* операторы де/сериализации;
|
||||||
|
* возможность получить PIVariant любого члена структуры по имени.
|
||||||
|
|
||||||
|
Параметры обработки:
|
||||||
|
* -s - не следовать "#include" внутри файлов;
|
||||||
|
* -I<include_dir> - добавить папку включения (например, -I.. -I../some_dir -I/usr/include);
|
||||||
|
* -D<define> - добавить макрос, PICODE всегда объявлен (например, -DMY_DEFINE добавит макрос MY_DEFINE).
|
||||||
|
|
||||||
|
Параметры создания:
|
||||||
|
* -A - создать всё;
|
||||||
|
* -M - создать метаинформацию (имена и типы всех членов, иерархия включения);
|
||||||
|
* -E - создать перечисления (списки перечислений);
|
||||||
|
* -S - создать операторы де/сериализации;
|
||||||
|
* -G - создать методы получения значений переменных по именам;
|
||||||
|
* -o <output_file> - имя файлов модели без расширения (например, "ccm" - создадутся файлы "ccm.h" и "ccm.cpp")
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
|
||||||
|
Для автоматизации кодогенерации существует CMake макрос pip_code_model, который сам вызывает pip_cmg и
|
||||||
|
следит за актуальностью модели.
|
||||||
|
|
||||||
|
Формат вызова макроса:
|
||||||
|
\code{.cmake}
|
||||||
|
pip_code_model(<out_var> file0 [file1 ...] [OPTIONS opt0 [opt1 ...] ] [NAME name])
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Параметры:
|
||||||
|
* out_var - имя переменной, куда будут записаны абсолютные пути сгенерённых файлов;
|
||||||
|
* file... - файлы для генерации, допускаются относительные или абсолютные пути;
|
||||||
|
* OPTIONS - передаваемые в pip_cmg параметры, например, "-Es";
|
||||||
|
* NAME - базовое имя файлов модели, если не указано, то используется "ccm_${PROJECT_NAME}".
|
||||||
|
|
||||||
|
Этот макрос сам включает все пути для PIP.
|
||||||
|
|
||||||
|
Для получения актуальных параметров pip_cmg можно вызывать "pip_cmg -v".
|
||||||
|
|
||||||
|
# Подробности
|
||||||
|
|
||||||
|
## Метаинформация
|
||||||
|
|
||||||
|
Метаинформация - это текстовое представление всех членов и методов структуры или класса C++.
|
||||||
|
Для доступа к ним используется PICodeInfo::classesInfo->value("name"), который возвращает
|
||||||
|
указатель на структуру PICodeInfo::ClassInfo, содержащую всю информацию о сущности.
|
||||||
|
|
||||||
|
В любой структуре PICodeInfo есть поле "MetaMap meta", содержащее произвольные
|
||||||
|
данные, видимые для кодогенератора, но невидимые для компилятора.
|
||||||
|
Для этого используется макрос PIMETA(), который необходимо вписать после объявления
|
||||||
|
переменной, метода либо сущности, например:
|
||||||
|
\code{.cpp}
|
||||||
|
struct MyStruct: Header PIMETA(type=in,port=5005) {
|
||||||
|
ushort calcChecksum() const PIMETA(show=true);
|
||||||
|
bool checkChecksum() const;
|
||||||
|
void setChecksum();
|
||||||
|
uchar block_id PIMETA(type=int) = 0;
|
||||||
|
};
|
||||||
|
enum FOV { // Поле зрения
|
||||||
|
fovWide PIMETA(label="Широкое",angle=90),
|
||||||
|
fovNormal PIMETA(label="Нормальное",angle=60),
|
||||||
|
fovNarrow PIMETA(label="Узкое",angle=30)
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
В этом примере в каждом месте, где указана PIMETA, её можно будет получить через "MetaMap meta".
|
||||||
|
|
||||||
|
## Перечисления
|
||||||
|
|
||||||
|
Перечисления записываются отдельно, для доступа к ним используется PICodeInfo::enumsInfo->value("name"),
|
||||||
|
который возвращает указатель на структуру PICodeInfo::EnumInfo, содержащую всю информацию о перечеслении.
|
||||||
|
|
||||||
|
## Операторы де/сериализации
|
||||||
|
|
||||||
|
Эти операторы создаются в h файле для всех сутрктур и классов, в которых есть хотя бы один член,
|
||||||
|
доступный для работы. Операторы работают с PIBinaryStream в двух вариантах - простом или через PIChunkStream.
|
||||||
|
|
||||||
|
Для каждой структуры можно указать режим де/сериализации с помощью фиксированного поля в PIMETA:
|
||||||
|
* нет указаний - работа через PIChunkStream;
|
||||||
|
* simple-stream - работа просто через PIBinaryStream;
|
||||||
|
* no-stream - не создавать операторы.
|
||||||
|
|
||||||
|
Например, для структуры
|
||||||
|
\code{.cpp}
|
||||||
|
struct DateTime {
|
||||||
|
uchar seconds;
|
||||||
|
uchar minutes;
|
||||||
|
uchar hours;
|
||||||
|
uchar days;
|
||||||
|
uchar months;
|
||||||
|
uchar years;
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
создадутся операторы
|
||||||
|
\code{.cpp}
|
||||||
|
BINARY_STREAM_WRITE(DateTime) {
|
||||||
|
PIChunkStream cs;
|
||||||
|
cs << cs.chunk(1, v.seconds);
|
||||||
|
cs << cs.chunk(2, v.minutes);
|
||||||
|
cs << cs.chunk(3, v.hours);
|
||||||
|
cs << cs.chunk(4, v.days);
|
||||||
|
cs << cs.chunk(5, v.months);
|
||||||
|
cs << cs.chunk(6, v.years);
|
||||||
|
s << cs.data();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
BINARY_STREAM_READ (DateTime) {
|
||||||
|
PIByteArray csba; s >> csba;
|
||||||
|
PIChunkStream cs(csba);
|
||||||
|
while (!cs.atEnd()) {
|
||||||
|
switch (cs.read()) {
|
||||||
|
case 1: cs.get(v.seconds); break;
|
||||||
|
case 2: cs.get(v.minutes); break;
|
||||||
|
case 3: cs.get(v.hours); break;
|
||||||
|
case 4: cs.get(v.days); break;
|
||||||
|
case 5: cs.get(v.months); break;
|
||||||
|
case 6: cs.get(v.years); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
, где порядок id последовательнен.
|
||||||
|
|
||||||
|
Для структуры
|
||||||
|
\code{.cpp}
|
||||||
|
struct DateTime PIMETA(simple-stream) {
|
||||||
|
uchar seconds;
|
||||||
|
uchar minutes;
|
||||||
|
uchar hours;
|
||||||
|
uchar days;
|
||||||
|
uchar months;
|
||||||
|
uchar years;
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
создадутся операторы
|
||||||
|
\code{.cpp}
|
||||||
|
BINARY_STREAM_WRITE(DateTime) {
|
||||||
|
s << v.seconds;
|
||||||
|
s << v.minutes;
|
||||||
|
s << v.hours;
|
||||||
|
s << v.days;
|
||||||
|
s << v.months;
|
||||||
|
s << v.years;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
BINARY_STREAM_READ (DateTime) {
|
||||||
|
s >> v.seconds;
|
||||||
|
s >> v.minutes;
|
||||||
|
s >> v.hours;
|
||||||
|
s >> v.days;
|
||||||
|
s >> v.months;
|
||||||
|
s >> v.years;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Для структуры
|
||||||
|
\code{.cpp}
|
||||||
|
struct DateTime PIMETA(no-stream) {
|
||||||
|
uchar seconds;
|
||||||
|
uchar minutes;
|
||||||
|
uchar hours;
|
||||||
|
uchar days;
|
||||||
|
uchar months;
|
||||||
|
uchar years;
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
не создадутся операторы
|
||||||
|
|
||||||
|
В режиме работы через PIChunkStream также можно указать индивидуальные id,
|
||||||
|
что очень полезно для сохранения обратной совместимости структур разных версий:
|
||||||
|
Для структуры
|
||||||
|
\code{.cpp}
|
||||||
|
struct DateTime {
|
||||||
|
PIMETA(id=10) uchar seconds;
|
||||||
|
PIMETA(id=11) uchar minutes;
|
||||||
|
PIMETA(id=12) uchar hours;
|
||||||
|
PIMETA(id=20) uchar days;
|
||||||
|
PIMETA(id=21) uchar months;
|
||||||
|
PIMETA(id=22) uchar years;
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
\code{.cpp}
|
||||||
|
BINARY_STREAM_WRITE(DateTime) {
|
||||||
|
PIChunkStream cs;
|
||||||
|
cs << cs.chunk(10, v.seconds);
|
||||||
|
cs << cs.chunk(11, v.minutes);
|
||||||
|
cs << cs.chunk(12, v.hours);
|
||||||
|
cs << cs.chunk(20, v.days);
|
||||||
|
cs << cs.chunk(21, v.months);
|
||||||
|
cs << cs.chunk(22, v.years);
|
||||||
|
s << cs.data();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
BINARY_STREAM_READ (DateTime) {
|
||||||
|
PIByteArray csba; s >> csba;
|
||||||
|
PIChunkStream cs(csba);
|
||||||
|
while (!cs.atEnd()) {
|
||||||
|
switch (cs.read()) {
|
||||||
|
case 10: cs.get(v.seconds); break;
|
||||||
|
case 11: cs.get(v.minutes); break;
|
||||||
|
case 12: cs.get(v.hours); break;
|
||||||
|
case 20: cs.get(v.days); break;
|
||||||
|
case 21: cs.get(v.months); break;
|
||||||
|
case 22: cs.get(v.years); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
Если в этом режиме какую-либо переменную надо проигнорировать, то вместо
|
||||||
|
числа id можно указать "-":
|
||||||
|
\code{.cpp}
|
||||||
|
struct DateTime {
|
||||||
|
PIMETA(id=10) uchar seconds;
|
||||||
|
PIMETA(id=11) uchar minutes;
|
||||||
|
PIMETA(id=-) uchar hours;
|
||||||
|
PIMETA(id=20) uchar days;
|
||||||
|
PIMETA(id=21) uchar months;
|
||||||
|
PIMETA(id=-) uchar years;
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
\code{.cpp}
|
||||||
|
BINARY_STREAM_WRITE(DateTime) {
|
||||||
|
PIChunkStream cs;
|
||||||
|
cs << cs.chunk(10, v.seconds);
|
||||||
|
cs << cs.chunk(11, v.minutes);
|
||||||
|
cs << cs.chunk(20, v.days);
|
||||||
|
cs << cs.chunk(21, v.months);
|
||||||
|
s << cs.data();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
BINARY_STREAM_READ (DateTime) {
|
||||||
|
PIByteArray csba; s >> csba;
|
||||||
|
PIChunkStream cs(csba);
|
||||||
|
while (!cs.atEnd()) {
|
||||||
|
switch (cs.read()) {
|
||||||
|
case 10: cs.get(v.seconds); break;
|
||||||
|
case 11: cs.get(v.minutes); break;
|
||||||
|
case 20: cs.get(v.days); break;
|
||||||
|
case 21: cs.get(v.months); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
# Интеграция в проект
|
||||||
|
|
||||||
|
При использовании CMake достаточно включить содержимое переменной out_var в приложение
|
||||||
|
или библиотеку, и включить через "#include" сгенерированный заголовочный файл в нужном месте.
|
||||||
|
После этого перечисления и метаинформация будут загружены в момент запуска, до int main(),
|
||||||
|
а операторы станут доступны через заголовочный файл.
|
||||||
|
|
||||||
|
CMakeLists.txt:
|
||||||
|
\code{.cmake}
|
||||||
|
project(myapp)
|
||||||
|
pip_code_model(CCM "structures.h" OPTIONS "-EMs")
|
||||||
|
add_executable(${PROJECT_NAME} ${CPPS} ${CCM})
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
C++:
|
||||||
|
\code{.cpp}
|
||||||
|
#include "ccm_myapp.h"
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
PICodeInfo::EnumInfo * ei = PICodeInfo::enumsInfo->value("MyEnum", 0);
|
||||||
|
if (ei) {
|
||||||
|
ei->members.forEach([](const PICodeInfo::EnumeratorInfo & e){piCout << e.name << "=" << e.value;});
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
117
doc/pages/iostream.md
Normal file
117
doc/pages/iostream.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
\~english \page iostream Input/Output stream
|
||||||
|
\~russian \page iostream Поток ввода/вывода
|
||||||
|
|
||||||
|
\~english
|
||||||
|
\~russian
|
||||||
|
%PIBinaryStream представляет собой интерфейс бинарной сериализации.
|
||||||
|
Не может быть использован в чистом виде, только в виде миксина или
|
||||||
|
готовых классов: PIByteArray и PIIOBinaryStream.
|
||||||
|
|
||||||
|
|
||||||
|
Используется для сохранения или чтения любых данных. Простые типы читаются/пишутся
|
||||||
|
как блоки памяти, если не созданы конкретные операторы. Сложные типы
|
||||||
|
([нетривиальные](https://ru.cppreference.com/w/cpp/types/is_trivially_copyable))
|
||||||
|
обязаны иметь операторы ввода/вывода, иначе возникнет ошибка компиляции.
|
||||||
|
|
||||||
|
Также поддерживаются контейнеры с типами по таким же правилам.
|
||||||
|
|
||||||
|
Перечисления интерпретируются как int, логические типы как один байт.
|
||||||
|
|
||||||
|
Операторы сохранения добавляют данные в конец потока, а операторы извлечения
|
||||||
|
берут данные из его начала.
|
||||||
|
|
||||||
|
Для облегчения написания операторов есть макросы:
|
||||||
|
* BINARY_STREAM_FRIEND(T) - объявить операторы с доступом к приватному
|
||||||
|
содержимому типа T, необязателен;
|
||||||
|
* BINARY_STREAM_WRITE(T) - запись в поток, "s" - объект потока, "v" - объект типа T;
|
||||||
|
* BINARY_STREAM_READ(T) - чтение из потока, "s" - объект потока, "v" - объект типа T.
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
\~\code{.cpp}
|
||||||
|
#include <pibytearray.h>
|
||||||
|
|
||||||
|
class MyType {
|
||||||
|
BINARY_STREAM_FRIEND(MyType);
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setInt(int v) {m_i = v;}
|
||||||
|
int getInt() const {return m_i;}
|
||||||
|
|
||||||
|
void setString(PIString v) {m_s = v;}
|
||||||
|
PIString getString() const {return m_s;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_i = 0;
|
||||||
|
PIString m_s;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
BINARY_STREAM_WRITE(MyType) {s << v.m_i << v.m_s; return s;}
|
||||||
|
BINARY_STREAM_READ (MyType) {s >> v.m_i >> v.m_s; return s;}
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]) {
|
||||||
|
MyType t_read, t_write;
|
||||||
|
t_write.setInt(10);
|
||||||
|
t_write.setString("text");
|
||||||
|
|
||||||
|
PIByteArray data;
|
||||||
|
data << t_write;
|
||||||
|
|
||||||
|
piCout << data.toHex();
|
||||||
|
|
||||||
|
data >> t_read;
|
||||||
|
piCout << t_read.getInt() << t_read.getString();
|
||||||
|
|
||||||
|
piCout << data.toHex();
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\~english Result:
|
||||||
|
\~russian Результат:
|
||||||
|
\~\code{.cpp}
|
||||||
|
0a000000040000007400650078007400
|
||||||
|
10 text
|
||||||
|
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
|
||||||
|
\~english
|
||||||
|
For store/restore custom data blocks this is PIMemoryBlock class. Stream
|
||||||
|
operators of this class simply store/restore data block to/from stream:
|
||||||
|
|
||||||
|
\~russian
|
||||||
|
Для сохранения/извлечения блоков произвольных данных используется класс PIMemoryBlock.
|
||||||
|
Потоковые операторы для него просто сохраняют/извлекают блоки байтов в/из потока:
|
||||||
|
|
||||||
|
\~\code{.cpp}
|
||||||
|
float a_read[10], a_write[10];
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
a_read [i] = 0.f;
|
||||||
|
a_write[i] = i / 10.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIByteArray data;
|
||||||
|
data << PIMemoryBlock(a_write, 10 * sizeof(float));
|
||||||
|
|
||||||
|
piCout << data.toHex();
|
||||||
|
|
||||||
|
data >> PIMemoryBlock(a_read, 10 * sizeof(float));
|
||||||
|
for (int i = 0; i < 10; ++i)
|
||||||
|
piCout << a_read[i];
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\~english Result:
|
||||||
|
\~russian Результат:
|
||||||
|
\~\code{.cpp}
|
||||||
|
00000000cdcccc3dcdcc4c3e9a99993ecdcccc3e0000003f9a99193f3333333fcdcc4c3f6666663f
|
||||||
|
0
|
||||||
|
0.1
|
||||||
|
0.2
|
||||||
|
0.3
|
||||||
|
0.4
|
||||||
|
0.5
|
||||||
|
0.6
|
||||||
|
0.7
|
||||||
|
0.8
|
||||||
|
0.9
|
||||||
|
\endcode
|
||||||
44
doc/pages/main.md
Normal file
44
doc/pages/main.md
Normal 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
104
doc/pages/summary.md
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
\~english \page summary Functionality summary
|
||||||
|
\~russian \page summary Сводка функциональности
|
||||||
|
|
||||||
|
\~english
|
||||||
|
|
||||||
|
* direct output to console (\a PICout)
|
||||||
|
* containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||||
|
* byte array (\a PIByteArray)
|
||||||
|
* serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream)
|
||||||
|
* string (\a PIConstChars, \a PIString, \a PIStringList)
|
||||||
|
* base object (events and handlers) (\a PIObject)
|
||||||
|
* multithreading
|
||||||
|
* thread (\a PIThread)
|
||||||
|
* blocking (\a PIMutex, \a PISpinlock)
|
||||||
|
* executor (\a PIThreadPoolExecutor)
|
||||||
|
* blocking dequeue (\a PIBlockingDequeue)
|
||||||
|
* timer (\a PITimer)
|
||||||
|
* tiling console (with widgets) (\a PIScreen)
|
||||||
|
* simple text rows
|
||||||
|
* scroll bar
|
||||||
|
* list
|
||||||
|
* button
|
||||||
|
* buttons group
|
||||||
|
* check box
|
||||||
|
* progress bar
|
||||||
|
* PICout output
|
||||||
|
* text input
|
||||||
|
* I/O devices
|
||||||
|
* base class (\a PIIODevice)
|
||||||
|
* file (\a PIFile)
|
||||||
|
* serial port (\a PISerial)
|
||||||
|
* ethernet (\a PIEthernet)
|
||||||
|
* USB (\a PIUSB)
|
||||||
|
* packets extractor (\a PIPacketExtractor)
|
||||||
|
* binary log (\a PIBinaryLog)
|
||||||
|
* complex I/O point (\a PIConnection)
|
||||||
|
* peering net node (\a PIPeer)
|
||||||
|
* connection quality diagnotic (\a PIDiagnostics)
|
||||||
|
* Run-time libraries
|
||||||
|
* abstract (\a PILibrary)
|
||||||
|
* plugin (\a PIPluginLoader)
|
||||||
|
* Mathematics
|
||||||
|
* complex numbers
|
||||||
|
* vectors (\a PIMathVector, \a PIMathVectorT)
|
||||||
|
* matrices (\a PIMathMatrix, \a PIMathMatrixT)
|
||||||
|
* quaternion (\a PIQuaternion)
|
||||||
|
* 2D geometry (\a PIPoint, \a PILine, \a PIRect)
|
||||||
|
* statistic (\a PIStatistic)
|
||||||
|
* CRC checksum (\a PICRC)
|
||||||
|
* Fourier transform (\a PIFFTW, \a PIFFT)
|
||||||
|
* expression evaluator (\a PIEvaluator)
|
||||||
|
* command-line arguments parser (\a PICLI)
|
||||||
|
* process (\a PIProcess)
|
||||||
|
|
||||||
|
\~russian
|
||||||
|
|
||||||
|
* общение с консолью (\a PICout)
|
||||||
|
* контейнеры (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
|
||||||
|
* байтовый массив (\a PIByteArray)
|
||||||
|
* сериализация (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream)
|
||||||
|
* строка (\a PIConstChars, \a PIString, \a PIStringList)
|
||||||
|
* базовый объект (события и обработчики) (\a PIObject)
|
||||||
|
* многопоточность
|
||||||
|
* поток (\a PIThread)
|
||||||
|
* блокировки (\a PIMutex, \a PISpinlock)
|
||||||
|
* исполнитель (\a PIThreadPoolExecutor)
|
||||||
|
* блокирующая очередь (\a PIBlockingDequeue)
|
||||||
|
* таймер (\a PITimer)
|
||||||
|
* тайлинговая консоль (с виджетами) (\a PIScreen)
|
||||||
|
* простой вывод строк
|
||||||
|
* скроллбар
|
||||||
|
* лист
|
||||||
|
* кнопка
|
||||||
|
* группа кнопок
|
||||||
|
* галочка
|
||||||
|
* прогрессбар
|
||||||
|
* вывод PICout
|
||||||
|
* текстовый ввод
|
||||||
|
* устройства ввода/вывода
|
||||||
|
* базовый класс (\a PIIODevice)
|
||||||
|
* файл (\a PIFile)
|
||||||
|
* последовательный порт (\a PISerial)
|
||||||
|
* ethernet (\a PIEthernet)
|
||||||
|
* USB (\a PIUSB)
|
||||||
|
* packets extractor (\a PIPacketExtractor)
|
||||||
|
* бинарный логфайл (\a PIBinaryLog)
|
||||||
|
* сложное составное устройство (\a PIConnection)
|
||||||
|
* пиринговая сеть (\a PIPeer)
|
||||||
|
* диагностика качества связи (\a PIDiagnostics)
|
||||||
|
* поддержка библиотек времени выполнения
|
||||||
|
* базовая функциональность (\a PILibrary)
|
||||||
|
* плагин (\a PIPluginLoader)
|
||||||
|
* Математика
|
||||||
|
* комплексные числа
|
||||||
|
* вектора (\a PIMathVector, \a PIMathVectorT)
|
||||||
|
* матрицы (\a PIMathMatrix, \a PIMathMatrixT)
|
||||||
|
* кватернион (\a PIQuaternion)
|
||||||
|
* 2D геометрия (\a PIPoint, \a PILine, \a PIRect)
|
||||||
|
* статистика (\a PIStatistic)
|
||||||
|
* CRC контрольная сумма (\a PICRC)
|
||||||
|
* преобразования Фурье (\a PIFFTW, \a PIFFT)
|
||||||
|
* вычислитель выражений (\a PIEvaluator)
|
||||||
|
* парсер аргументов командной строки (\a PICLI)
|
||||||
|
* процесс (\a PIProcess)
|
||||||
128
doc/pages/using_basic.md
Normal file
128
doc/pages/using_basic.md
Normal 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
BIN
doc/pip.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
29
library.json
Normal file
29
library.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
|
|
||||||
PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(ð), tcp(&streampacker) {
|
PICloudBase::PICloudBase() : eth(PIEthernet::TCP_Client), streampacker(ð), tcp(&streampacker) {
|
||||||
|
eth.setDebug(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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(ð, connected, [this](){tcp.sendStart();});
|
is_deleted = false;
|
||||||
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
|
// setReopenEnabled(false);
|
||||||
|
CONNECTL(ð, connected, [this](){opened_ = true; tcp.sendStart();});
|
||||||
|
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
|
||||||
CONNECTL(ð, disconnected, [this](bool){
|
CONNECTL(ð, disconnected, [this](bool){
|
||||||
piCoutObj << "disconnected";
|
if (is_deleted) return;
|
||||||
|
bool need_disconn = is_connected;
|
||||||
|
//piCoutObj << "eth disconnected";
|
||||||
|
static_cast<PIThread*>(ð)->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) {
|
ssize_t PICloudClient::readDevice(void * read_to, ssize_t max_size) {
|
||||||
// piCoutObj << "readDevice";
|
if (is_deleted) return -1;
|
||||||
if (!is_connected) return -1;
|
//piCoutObj << "readDevice";
|
||||||
|
if (!is_connected && eth.isClosed()) openDevice();
|
||||||
|
ssize_t 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) {
|
ssize_t PICloudClient::writeDevice(const void * data, ssize_t 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*>(ð)->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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,18 @@ PICloudServer::PICloudServer(const PIString & path, PIIODevice::DeviceMode mode)
|
|||||||
tcp.setRole(PICloud::TCP::Server);
|
tcp.setRole(PICloud::TCP::Server);
|
||||||
tcp.setServerName(server_name);
|
tcp.setServerName(server_name);
|
||||||
setName("cloud_server__" + server_name);
|
setName("cloud_server__" + server_name);
|
||||||
CONNECTU(&streampacker, packetReceiveEvent, this, _readed);
|
CONNECT1(void, PIByteArray, &streampacker, packetReceiveEvent, this, _readed);
|
||||||
CONNECTL(ð, connected, [this](){tcp.sendStart();});
|
CONNECTL(ð, connected, [this](){opened_ = true; piCoutObj << "connected"; tcp.sendStart();});
|
||||||
CONNECTL(ð, disconnected, [this](bool){
|
CONNECTL(ð, disconnected, [this](bool){
|
||||||
piCoutObj << "disconnected";
|
piCoutObj << "disconnected";
|
||||||
|
static_cast<PIThread*>(ð)->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();
|
||||||
@@ -80,14 +88,15 @@ bool PICloudServer::closeDevice() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int PICloudServer::readDevice(void * read_to, int max_size) {
|
ssize_t PICloudServer::readDevice(void * read_to, ssize_t max_size) {
|
||||||
//piCoutObj << "readDevice";
|
//piCoutObj << "readDevice";
|
||||||
piMSleep(eth.readTimeout());
|
if (!opened_) openDevice();
|
||||||
|
else piMSleep(eth.readTimeout());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int PICloudServer::writeDevice(const void * data, int max_size) {
|
ssize_t PICloudServer::writeDevice(const void * data, ssize_t max_size) {
|
||||||
//piCoutObj << "writeDevice";
|
//piCoutObj << "writeDevice";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -126,28 +135,32 @@ 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) {
|
ssize_t PICloudServer::Client::readDevice(void * read_to, ssize_t max_size) {
|
||||||
if (!is_connected) return -1;
|
if (!is_connected) return -1;
|
||||||
|
ssize_t sz = -1;
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int PICloudServer::Client::writeDevice(const void * data, int size) {
|
ssize_t PICloudServer::Client::writeDevice(const void * data, ssize_t size) {
|
||||||
return server->sendData(PIByteArray(data, size), client_id);
|
return server->sendData(PIByteArray(data, size), client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,9 +187,9 @@ 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);
|
CONNECT1(void, PIObject *, c, deleted, this, clientDeleted);
|
||||||
clients_mutex.lock();
|
clients_mutex.lock();
|
||||||
clients_ << c;
|
clients_ << c;
|
||||||
index_clients.insert(id, c);
|
index_clients.insert(id, c);
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -150,14 +168,14 @@ PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
|
|||||||
|
|
||||||
|
|
||||||
uint PICloud::TCP::parseConnect(PIByteArray & ba) {
|
uint PICloud::TCP::parseConnect(PIByteArray & ba) {
|
||||||
uint ret;
|
uint ret = 0;
|
||||||
ba >> ret;
|
ba >> ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
|
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
|
||||||
uint ret;
|
uint ret = 0;
|
||||||
ba >> ret;
|
ba >> ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -53,7 +53,7 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
|
|||||||
|
|
||||||
PIByteArray piDecompress(const PIByteArray & zba) {
|
PIByteArray piDecompress(const PIByteArray & zba) {
|
||||||
#ifdef PIP_COMPRESS
|
#ifdef PIP_COMPRESS
|
||||||
ullong sz;
|
ullong sz = 0;
|
||||||
if (zba.size() < sizeof(ullong)) {
|
if (zba.size() < sizeof(ullong)) {
|
||||||
piCout << "[PICompress]" << "Error: invalid input";
|
piCout << "[PICompress]" << "Error: invalid input";
|
||||||
return zba;
|
return zba;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -50,29 +51,6 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
|
|||||||
PIScreen::SystemConsole::SystemConsole() {
|
PIScreen::SystemConsole::SystemConsole() {
|
||||||
width = height = pwidth = pheight = 0;
|
width = height = pwidth = pheight = 0;
|
||||||
mouse_x = mouse_y = -1;
|
mouse_x = mouse_y = -1;
|
||||||
int w, h;
|
|
||||||
#ifdef WINDOWS
|
|
||||||
PRIVATE->ulcoord.X = 0;
|
|
||||||
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
|
||||||
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
|
|
||||||
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
|
||||||
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
|
||||||
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
|
|
||||||
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
|
|
||||||
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
|
||||||
#else
|
|
||||||
# ifdef FREERTOS
|
|
||||||
w = 80;
|
|
||||||
h = 24;
|
|
||||||
# else
|
|
||||||
winsize ws;
|
|
||||||
ioctl(0, TIOCGWINSZ, &ws);
|
|
||||||
w = ws.ws_col;
|
|
||||||
h = ws.ws_row;
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
resize(w, h);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -85,6 +63,29 @@ PIScreen::SystemConsole::~SystemConsole() {
|
|||||||
|
|
||||||
|
|
||||||
void PIScreen::SystemConsole::begin() {
|
void PIScreen::SystemConsole::begin() {
|
||||||
|
int w, h;
|
||||||
|
#ifdef WINDOWS
|
||||||
|
PRIVATE->ulcoord.X = 0;
|
||||||
|
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||||
|
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
|
||||||
|
w = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
||||||
|
h = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
||||||
|
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
|
||||||
|
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
|
||||||
|
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
||||||
|
#else
|
||||||
|
# ifdef MICRO_PIP
|
||||||
|
w = 80;
|
||||||
|
h = 24;
|
||||||
|
# else
|
||||||
|
winsize ws;
|
||||||
|
ioctl(0, TIOCGWINSZ, &ws);
|
||||||
|
w = ws.ws_col;
|
||||||
|
h = ws.ws_row;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
resize(w, h);
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
|
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
|
||||||
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
||||||
@@ -92,6 +93,7 @@ void PIScreen::SystemConsole::begin() {
|
|||||||
PRIVATE->bc.Y = 0;
|
PRIVATE->bc.Y = 0;
|
||||||
#endif
|
#endif
|
||||||
clear();
|
clear();
|
||||||
|
clearScreen();
|
||||||
hideCursor();
|
hideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,16 +110,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 +143,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 +220,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 +297,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
|
||||||
|
|
||||||
@@ -392,18 +392,17 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe
|
|||||||
needLockRun(true);
|
needLockRun(true);
|
||||||
mouse_ = false;
|
mouse_ = false;
|
||||||
ret_func = slot;
|
ret_func = slot;
|
||||||
tile_focus = tile_dialog = 0;
|
tile_focus = tile_dialog = nullptr;
|
||||||
root.screen = this;
|
root.screen = this;
|
||||||
listener = new PIKbdListener(key_eventS, this, startNow);
|
listener = new PIKbdListener(key_eventS, this, startNow);
|
||||||
CONNECTU(listener, mouseEvent, this, mouse_event);
|
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event);
|
||||||
CONNECTU(listener, wheelEvent, this, wheel_event);
|
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event);
|
||||||
if (startNow) start();
|
if (startNow) start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PIScreen::~PIScreen() {
|
PIScreen::~PIScreen() {
|
||||||
if (isRunning())
|
if (isRunning()) stop();
|
||||||
stop();
|
|
||||||
PIThread::waitForFinish(10);
|
PIThread::waitForFinish(10);
|
||||||
listener->waitForFinish(10);
|
listener->waitForFinish(10);
|
||||||
delete listener;
|
delete listener;
|
||||||
|
|||||||
@@ -538,12 +538,11 @@ TilePICout::TilePICout(const PIString & n): TileList(n) {
|
|||||||
max_lines = 1024;
|
max_lines = 1024;
|
||||||
selection_mode = TileList::SingleSelection;
|
selection_mode = TileList::SingleSelection;
|
||||||
PICout::setOutputDevices(PICout::Buffer);
|
PICout::setOutputDevices(PICout::Buffer);
|
||||||
PICout::setBufferActive(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TilePICout::drawEvent(PIScreenDrawer * d) {
|
void TilePICout::drawEvent(PIScreenDrawer * d) {
|
||||||
PIString out = PICout::buffer(true);
|
PIString out = PICout::getBufferAndClear();
|
||||||
if (!out.isEmpty()) {
|
if (!out.isEmpty()) {
|
||||||
PIStringList l = out.split("\n");
|
PIStringList l = out.split("\n");
|
||||||
bool scroll = (cur == content.size_s() - 1) || !has_focus;
|
bool scroll = (cur == content.size_s() - 1) || !has_focus;
|
||||||
@@ -689,13 +688,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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -154,7 +151,7 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
|||||||
//piCout << "mcast " << ce->readAddress() << ce->sendAddress();
|
//piCout << "mcast " << ce->readAddress() << ce->sendAddress();
|
||||||
if (ce->open()) {
|
if (ce->open()) {
|
||||||
eth_mcast << ce;
|
eth_mcast << ce;
|
||||||
CONNECTU(ce, threadedReadEvent, this, mcastRead);
|
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
|
||||||
} else {
|
} else {
|
||||||
delete ce;
|
delete ce;
|
||||||
}
|
}
|
||||||
@@ -176,7 +173,7 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
|||||||
//piCout << "bcast " << ce->readAddress() << ce->sendAddress();
|
//piCout << "bcast " << ce->readAddress() << ce->sendAddress();
|
||||||
if (ce->open()) {
|
if (ce->open()) {
|
||||||
eth_mcast << ce;
|
eth_mcast << ce;
|
||||||
CONNECTU(ce, threadedReadEvent, this, mcastRead);
|
CONNECT2(void, const uchar *, ssize_t, ce, threadedReadEvent, this, mcastRead);
|
||||||
} else {
|
} else {
|
||||||
delete ce;
|
delete ce;
|
||||||
}
|
}
|
||||||
@@ -184,7 +181,6 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
|||||||
eth_mcast << ce;
|
eth_mcast << ce;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_channels[Loopback]) {
|
if (_channels[Loopback]) {
|
||||||
@@ -193,7 +189,7 @@ void PIBroadcast::initAll(PIVector<PIEthernet::Address> al) {
|
|||||||
eth_lo->setName("PIMulticast_loopback");
|
eth_lo->setName("PIMulticast_loopback");
|
||||||
if (!_send_only) {
|
if (!_send_only) {
|
||||||
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
|
eth_lo->setParameter(PIEthernet::ReuseAddress, false);
|
||||||
CONNECTU(eth_lo, threadedReadEvent, this, mcastRead);
|
CONNECT2(void, const uchar *, ssize_t, eth_lo, threadedReadEvent, this, mcastRead);
|
||||||
for (int i = 0; i < lo_pcnt; ++i) {
|
for (int i = 0; i < lo_pcnt; ++i) {
|
||||||
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
|
eth_lo->setReadAddress("127.0.0.1", lo_port + i);
|
||||||
if (eth_lo->open()) {
|
if (eth_lo->open()) {
|
||||||
@@ -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,34 +220,35 @@ 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIBroadcast::mcastRead(uchar * data, int size) {
|
void PIBroadcast::mcastRead(const uchar * data, ssize_t size) {
|
||||||
PIByteArray cd = decryptData(PIByteArray(data, size));
|
PIByteArray cd = decryptData(PIByteArray(data, size));
|
||||||
if (cd.isEmpty()) return;
|
if (cd.isEmpty()) return;
|
||||||
received(cd);
|
received(cd);
|
||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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,36 +101,17 @@ 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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PIStreamPacker::received(uchar * readed, int size) {
|
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
|
||||||
received(PIByteArray(readed, size));
|
received(PIByteArray(readed, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,35 +195,9 @@ void PIStreamPacker::received(const PIByteArray & data) {
|
|||||||
|
|
||||||
void PIStreamPacker::assignDevice(PIIODevice * dev) {
|
void PIStreamPacker::assignDevice(PIIODevice * dev) {
|
||||||
if (!dev) return;
|
if (!dev) return;
|
||||||
if (!dev->infoFlags()[PIIODevice::Reliable])
|
if (!dev->infoFlags()[PIIODevice::Reliable]) {
|
||||||
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
|
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
|
||||||
CONNECTU(dev, threadedReadEvent, this, received);
|
}
|
||||||
CONNECTU(this, sendRequest, dev, write);
|
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
|
||||||
}
|
CONNECT1(void, PIByteArray, 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.;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -39,25 +42,29 @@ public:
|
|||||||
void setServerName(const PIString & server_name);
|
void setServerName(const PIString & server_name);
|
||||||
void setKeepConnection(bool on);
|
void setKeepConnection(bool on);
|
||||||
bool isConnected() const {return is_connected;}
|
bool isConnected() const {return is_connected;}
|
||||||
|
ssize_t bytesAvailable() const override {return buff.size();}
|
||||||
|
|
||||||
EVENT(connected)
|
EVENT(connected);
|
||||||
EVENT(disconnected)
|
EVENT(disconnected);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool openDevice();
|
bool openDevice() override;
|
||||||
bool closeDevice();
|
bool closeDevice() override;
|
||||||
int readDevice(void * read_to, int max_size);
|
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||||
int writeDevice(const void * data, int size);
|
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||||
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
|
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,24 +32,25 @@
|
|||||||
|
|
||||||
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);
|
||||||
virtual ~Client();
|
virtual ~Client();
|
||||||
protected:
|
protected:
|
||||||
bool openDevice();
|
bool openDevice() override;
|
||||||
bool closeDevice();
|
bool closeDevice() override;
|
||||||
int readDevice(void * read_to, int max_size);
|
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||||
int writeDevice(const void * data, int size);
|
ssize_t writeDevice(const void * data, ssize_t size) override;
|
||||||
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
|
DeviceInfoFlags deviceInfoFlags() const override {return PIIODevice::Reliable;}
|
||||||
|
ssize_t bytesAvailable() const override {return buff.size();}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void pushBuffer(const PIByteArray & ba);
|
void pushBuffer(const PIByteArray & ba);
|
||||||
@@ -62,13 +66,13 @@ public:
|
|||||||
|
|
||||||
PIVector<PICloudServer::Client *> clients() const;
|
PIVector<PICloudServer::Client *> clients() const;
|
||||||
|
|
||||||
EVENT1(newConnection, PICloudServer::Client * , client)
|
EVENT1(newConnection, PICloudServer::Client * , client);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool openDevice();
|
bool openDevice() override;
|
||||||
bool closeDevice();
|
bool closeDevice() override;
|
||||||
int readDevice(void * read_to, int max_size);
|
ssize_t readDevice(void * read_to, ssize_t max_size) override;
|
||||||
int writeDevice(const void * data, int max_size);
|
ssize_t writeDevice(const void * data, ssize_t max_size) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EVENT_HANDLER1(void, _readed, PIByteArray &, ba);
|
EVENT_HANDLER1(void, _readed, PIByteArray &, ba);
|
||||||
@@ -78,6 +82,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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
/*! @file picodeinfo.h
|
/*! \file picodeinfo.h
|
||||||
* @brief C++ code info structs
|
* \ingroup Code
|
||||||
*/
|
* \~\brief
|
||||||
|
* \~english C++ code info structs. See \ref code_model.
|
||||||
|
* \~russian Структуры для C++ кода. Подробнее \ref code_model.
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
PIP - Platform Independent Primitives
|
PIP - Platform Independent Primitives
|
||||||
C++ code info structs
|
C++ code info structs
|
||||||
@@ -24,21 +27,31 @@
|
|||||||
#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;
|
||||||
|
|
||||||
|
//! \~english Namespace contains structures for code generation. See \ref code_model.
|
||||||
|
//! \~russian Пространство имен содержит структуры для кодогенерации. Подробнее \ref code_model.
|
||||||
namespace PICodeInfo {
|
namespace PICodeInfo {
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english
|
||||||
|
//! Type modifiers
|
||||||
|
//! \~russian
|
||||||
|
//! Модификаторы типа
|
||||||
enum TypeFlag {
|
enum TypeFlag {
|
||||||
NoFlag,
|
NoFlag,
|
||||||
Const = 0x01,
|
Const /** const */ = 0x01,
|
||||||
Static = 0x02,
|
Static /** static */ = 0x02,
|
||||||
Mutable = 0x04,
|
Mutable /** mutable */ = 0x04,
|
||||||
Volatile = 0x08,
|
Volatile /** volatile */ = 0x08,
|
||||||
Inline = 0x10,
|
Inline /** inline */ = 0x10,
|
||||||
Virtual = 0x20,
|
Virtual /** virtual */ = 0x20,
|
||||||
Extern = 0x40
|
Extern /** extern */ = 0x40
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
|
typedef PIFlags<PICodeInfo::TypeFlag> TypeFlags;
|
||||||
@@ -46,47 +59,145 @@ typedef PIMap<PIString, PIString> MetaMap;
|
|||||||
typedef PIByteArray(*AccessValueFunction)(const void *, const char *);
|
typedef PIByteArray(*AccessValueFunction)(const void *, const char *);
|
||||||
typedef const char*(*AccessTypeFunction)(const char *);
|
typedef const char*(*AccessTypeFunction)(const char *);
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Type information
|
||||||
|
//! \~russian Информация о типе
|
||||||
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;}
|
||||||
|
|
||||||
|
//! \~english Returns if variable if bitfield
|
||||||
|
//! \~russian Возвращает битовым ли полем является переменная
|
||||||
bool isBitfield() const {return bits > 0;}
|
bool isBitfield() const {return bits > 0;}
|
||||||
|
|
||||||
|
//! \~english Custom PIMETA content
|
||||||
|
//! \~russian Произвольное содержимое PIMETA
|
||||||
MetaMap meta;
|
MetaMap meta;
|
||||||
PIString name;
|
|
||||||
PIString type;
|
//! \~english Name
|
||||||
|
//! \~russian Имя
|
||||||
|
PIConstChars name;
|
||||||
|
|
||||||
|
//! \~english Type
|
||||||
|
//! \~russian Тип
|
||||||
|
PIConstChars type;
|
||||||
|
|
||||||
|
//! \~english Modifiers
|
||||||
|
//! \~russian Модификаторы
|
||||||
PICodeInfo::TypeFlags flags;
|
PICodeInfo::TypeFlags flags;
|
||||||
|
|
||||||
|
//! \~english Bitfield variable bit count
|
||||||
|
//! \~russian Количество бит битового поля
|
||||||
int bits;
|
int bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Method information
|
||||||
|
//! \~russian Информация о методе
|
||||||
struct PIP_EXPORT FunctionInfo {
|
struct PIP_EXPORT FunctionInfo {
|
||||||
|
|
||||||
|
//! \~english Custom PIMETA content
|
||||||
|
//! \~russian Произвольное содержимое PIMETA
|
||||||
MetaMap meta;
|
MetaMap meta;
|
||||||
PIString name;
|
|
||||||
|
//! \~english Name
|
||||||
|
//! \~russian Имя
|
||||||
|
PIConstChars name;
|
||||||
|
|
||||||
|
//! \~english Return type
|
||||||
|
//! \~russian Возвращаемые тип
|
||||||
TypeInfo return_type;
|
TypeInfo return_type;
|
||||||
|
|
||||||
|
//! \~english Arguments types
|
||||||
|
//! \~russian Типы аргументов
|
||||||
PIVector<PICodeInfo::TypeInfo> arguments;
|
PIVector<PICodeInfo::TypeInfo> arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Class or struct information
|
||||||
|
//! \~russian Информация о классе или структуре
|
||||||
struct PIP_EXPORT ClassInfo {
|
struct PIP_EXPORT ClassInfo {
|
||||||
ClassInfo() {has_name = true;}
|
ClassInfo() {has_name = true;}
|
||||||
|
|
||||||
|
//! \~english Custom PIMETA content
|
||||||
|
//! \~russian Произвольное содержимое PIMETA
|
||||||
MetaMap meta;
|
MetaMap meta;
|
||||||
|
|
||||||
|
//! \~english Has name or not
|
||||||
|
//! \~russian Имеет или нет имя
|
||||||
bool has_name;
|
bool has_name;
|
||||||
PIString type;
|
|
||||||
PIString name;
|
//! \~english Type
|
||||||
PIStringList parents;
|
//! \~russian Тип
|
||||||
|
PIConstChars type;
|
||||||
|
|
||||||
|
//! \~english Name
|
||||||
|
//! \~russian Имя
|
||||||
|
PIConstChars name;
|
||||||
|
|
||||||
|
//! \~english Parent names
|
||||||
|
//! \~russian Имена родителей
|
||||||
|
PIVector<PIConstChars> parents;
|
||||||
|
|
||||||
|
//! \~english Variables
|
||||||
|
//! \~russian Переменные
|
||||||
PIVector<PICodeInfo::TypeInfo> variables;
|
PIVector<PICodeInfo::TypeInfo> variables;
|
||||||
|
|
||||||
|
//! \~english Methods
|
||||||
|
//! \~russian Методы
|
||||||
PIVector<PICodeInfo::FunctionInfo> functions;
|
PIVector<PICodeInfo::FunctionInfo> functions;
|
||||||
|
|
||||||
|
//! \~english Subclass list
|
||||||
|
//! \~russian Список наследников
|
||||||
PIVector<PICodeInfo::ClassInfo * > children_info;
|
PIVector<PICodeInfo::ClassInfo * > children_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Enumerator information
|
||||||
|
//! \~russian Информация об элементе перечисления
|
||||||
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());}
|
||||||
|
|
||||||
|
//! \~english Custom PIMETA content
|
||||||
|
//! \~russian Произвольное содержимое PIMETA
|
||||||
MetaMap meta;
|
MetaMap meta;
|
||||||
PIString name;
|
|
||||||
|
//! \~english Name
|
||||||
|
//! \~russian Имя
|
||||||
|
PIConstChars name;
|
||||||
|
|
||||||
|
//! \~english Value
|
||||||
|
//! \~russian Значение
|
||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Enum information
|
||||||
|
//! \~russian Информация о перечислении
|
||||||
struct PIP_EXPORT EnumInfo {
|
struct PIP_EXPORT EnumInfo {
|
||||||
|
|
||||||
|
//! \~english Returns member name with value "value"
|
||||||
|
//! \~russian Возвращает имя элемента со значением "value"
|
||||||
PIString memberName(int value) const;
|
PIString memberName(int value) const;
|
||||||
|
|
||||||
|
//! \~english Returns member value with name "name"
|
||||||
|
//! \~russian Возвращает значение элемента с именем "name"
|
||||||
int memberValue(const PIString & name) const;
|
int memberValue(const PIString & name) const;
|
||||||
|
|
||||||
|
//! \~english Returns as PIVariantTypes::Enum
|
||||||
|
//! \~russian Возвращает как PIVariantTypes::Enum
|
||||||
|
PIVariantTypes::Enum toPIVariantEnum();
|
||||||
|
|
||||||
|
//! \~english Custom PIMETA content
|
||||||
|
//! \~russian Произвольное содержимое PIMETA
|
||||||
MetaMap meta;
|
MetaMap meta;
|
||||||
PIString name;
|
|
||||||
|
//! \~english Name
|
||||||
|
//! \~russian Имя
|
||||||
|
PIConstChars name;
|
||||||
|
|
||||||
|
//! \~english Members
|
||||||
|
//! \~russian Элементы
|
||||||
PIVector<PICodeInfo::EnumeratorInfo> members;
|
PIVector<PICodeInfo::EnumeratorInfo> members;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,22 +218,22 @@ inline PICout operator <<(PICout s, const PICodeInfo::TypeInfo & v) {
|
|||||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value << " Meta" << v.meta; return s;}
|
inline PICout operator <<(PICout s, const PICodeInfo::EnumeratorInfo & v) {s << v.name << " = " << v.value << " Meta" << v.meta; return s;}
|
||||||
|
|
||||||
inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
inline PICout operator <<(PICout s, const PICodeInfo::ClassInfo & v) {
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
s << "class " << v.name;
|
s << "class " << v.name;
|
||||||
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,43 +242,51 @@ 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";
|
||||||
s.restoreControl();
|
s.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
|
inline PICout operator <<(PICout s, const PICodeInfo::EnumInfo & v) {
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
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 << ", ";
|
||||||
s << PICoutManipulators::Tab << i << "\n";
|
s << PICoutManipulators::Tab << i << "\n";
|
||||||
}
|
}
|
||||||
s << "}\n";
|
s << "}\n";
|
||||||
s.restoreControl();
|
s.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern PIP_EXPORT PIMap<PIString, PICodeInfo::ClassInfo * > * classesInfo;
|
|
||||||
extern PIP_EXPORT PIMap<PIString, PICodeInfo::EnumInfo * > * enumsInfo;
|
//! \~english Pointer to single storage of PICodeInfo::ClassInfo, access by name
|
||||||
extern PIP_EXPORT PIMap<PIString, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
//! \~russian Указатель на единое хренилище PICodeInfo::ClassInfo, доступ по имени
|
||||||
extern PIP_EXPORT PIMap<PIString, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::ClassInfo * > * classesInfo;
|
||||||
|
|
||||||
|
//! \~english Pointer to single storage of PICodeInfo::EnumInfo, access by name
|
||||||
|
//! \~russian Указатель на единое хренилище PICodeInfo::EnumInfo, доступ по имени
|
||||||
|
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::EnumInfo * > * enumsInfo;
|
||||||
|
|
||||||
|
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessValueFunction> * accessValueFunctions;
|
||||||
|
|
||||||
|
extern PIP_EXPORT PIMap<PIConstChars, PICodeInfo::AccessTypeFunction> * accessTypeFunctions;
|
||||||
|
|
||||||
inline PIByteArray getMemberValue(const void * p, const char * class_name, const char * member_name) {
|
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 +307,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_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,39 @@
|
|||||||
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.
|
||||||
|
//! See \ref code_model.
|
||||||
|
//!
|
||||||
|
//! \~russian
|
||||||
|
//! Эти файлы обеспечивают разбор C++ кода и хранение результатов работы утилиты \a pip_cmg.
|
||||||
|
//! Подробнее \ref code_model.
|
||||||
|
//!
|
||||||
|
//! \~\authors
|
||||||
|
//! \~english
|
||||||
|
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||||
|
//! Andrey Bychkov work.a.b@yandex.ru;
|
||||||
|
//! \~russian
|
||||||
|
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||||
|
//! Андрей Бычков work.a.b@yandex.ru;
|
||||||
|
//!
|
||||||
|
|
||||||
#ifndef PICODEMODULE_H
|
#ifndef PICODEMODULE_H
|
||||||
#define PICODEMODULE_H
|
#define PICODEMODULE_H
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -998,7 +1050,7 @@ PIString PICodeParser::procMacros(PIString fc) {
|
|||||||
if (ifcnt > 0) ifcnt--;
|
if (ifcnt > 0) ifcnt--;
|
||||||
else {
|
else {
|
||||||
//piCout << "main endif" << skip << grab;
|
//piCout << "main endif" << skip << grab;
|
||||||
if (grab) pfc << procMacros(nfc);
|
if (grab) pfc += procMacros(nfc);
|
||||||
skip = grab = false;
|
skip = grab = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1007,7 +1059,7 @@ PIString PICodeParser::procMacros(PIString fc) {
|
|||||||
//piCout << "main elif" << skip << grab << cond_ok;
|
//piCout << "main elif" << skip << grab << cond_ok;
|
||||||
if (cond_ok) {
|
if (cond_ok) {
|
||||||
if (grab) {
|
if (grab) {
|
||||||
pfc << procMacros(nfc);
|
pfc += procMacros(nfc);
|
||||||
skip = true; grab = false;
|
skip = true; grab = false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -1023,12 +1075,12 @@ PIString PICodeParser::procMacros(PIString fc) {
|
|||||||
}
|
}
|
||||||
if (mif.left(4) == s_else && ifcnt == 0) {
|
if (mif.left(4) == s_else && ifcnt == 0) {
|
||||||
//piCout << "main else" << skip << grab;
|
//piCout << "main else" << skip << grab;
|
||||||
if (grab) pfc << procMacros(nfc);
|
if (grab) pfc += procMacros(nfc);
|
||||||
if (skip && !cond_ok) {skip = false; grab = true;}
|
if (skip && !cond_ok) {skip = false; grab = true;}
|
||||||
else {skip = true; grab = false;}
|
else {skip = true; grab = false;}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (grab) nfc << line << '\n';
|
if (grab) nfc += line + '\n';
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mif.left(2) == s_if) {
|
if (mif.left(2) == s_if) {
|
||||||
@@ -1043,8 +1095,8 @@ PIString PICodeParser::procMacros(PIString fc) {
|
|||||||
//return false; /// WARNING: now skip errors
|
//return false; /// WARNING: now skip errors
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (grab) nfc << line << '\n';
|
if (grab) nfc += line + '\n';
|
||||||
else if (!skip) pfc << line << '\n';
|
else if (!skip) pfc += line + '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pfc;
|
return pfc;
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,12 +28,12 @@
|
|||||||
|
|
||||||
#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
|
||||||
{
|
{
|
||||||
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
|
PIOBJECT_SUBCLASS(PIKbdListener, PIThread);
|
||||||
friend class PIConsole;
|
friend class PIConsole;
|
||||||
friend class PITerminal;
|
friend class PITerminal;
|
||||||
public:
|
public:
|
||||||
@@ -173,28 +176,28 @@ public:
|
|||||||
EVENT_HANDLER(void, setActive) {setActive(true);}
|
EVENT_HANDLER(void, setActive) {setActive(true);}
|
||||||
EVENT_HANDLER1(void, setActive, bool, yes);
|
EVENT_HANDLER1(void, setActive, bool, yes);
|
||||||
|
|
||||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
|
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data);
|
||||||
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data)
|
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data);
|
||||||
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data)
|
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data);
|
||||||
|
|
||||||
//! \handlers
|
//! \handlers
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! \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
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -202,9 +205,9 @@ public:
|
|||||||
static PIKbdListener * instance() {return _object;}
|
static PIKbdListener * instance() {return _object;}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void begin();
|
void begin() override;
|
||||||
void run() {readKeyboard();}
|
void run() override {readKeyboard();}
|
||||||
void end();
|
void end() override;
|
||||||
|
|
||||||
#ifndef WINDOWS
|
#ifndef WINDOWS
|
||||||
struct PIP_EXPORT EscSeq {
|
struct PIP_EXPORT EscSeq {
|
||||||
@@ -244,13 +247,27 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << v.modifiers; return s;}
|
//! \relatesalso PIBinaryStream
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::MouseEvent & v) {s << v.x << v.y << (int)v.action << v.buttons << v.modifiers; return s;}
|
//! \~english Store operator
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::WheelEvent & v) {s << (*(PIKbdListener::MouseEvent*)&v) << (uchar)v.direction; return s;}
|
//! \~russian Оператор сохранения
|
||||||
|
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {s << v.x << v.y << v.action << v.buttons << v.modifiers; return s;}
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Restore operator
|
||||||
|
//! \~russian Оператор извлечения
|
||||||
|
BINARY_STREAM_READ (PIKbdListener::MouseEvent) {s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers; return s;}
|
||||||
|
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Store operator
|
||||||
|
//! \~russian Оператор сохранения
|
||||||
|
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {s << (*(PIKbdListener::MouseEvent*)&v) << v.direction; return s;}
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Restore operator
|
||||||
|
//! \~russian Оператор извлечения
|
||||||
|
BINARY_STREAM_READ (PIKbdListener::WheelEvent) {s >> (*(PIKbdListener::MouseEvent*)&v) >> v.direction; return s;}
|
||||||
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {s >> v.key >> v.modifiers; return s;}
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::MouseEvent & v) {int a(0); s >> v.x >> v.y >> a >> v.buttons >> v.modifiers; v.action = (PIKbdListener::MouseAction)a; return s;}
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::WheelEvent & v) {uchar d(0); s >> (*(PIKbdListener::MouseEvent*)&v) >> d; v.direction = d; return s;}
|
|
||||||
|
|
||||||
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
|
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
|
||||||
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)
|
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -30,7 +33,7 @@
|
|||||||
|
|
||||||
class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
|
class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
|
||||||
{
|
{
|
||||||
PIOBJECT_SUBCLASS(PIScreen, PIThread)
|
PIOBJECT_SUBCLASS(PIScreen, PIThread);
|
||||||
class SystemConsole;
|
class SystemConsole;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -73,30 +76,30 @@ public:
|
|||||||
EVENT_HANDLER0(void, stop) {stop(false);}
|
EVENT_HANDLER0(void, stop) {stop(false);}
|
||||||
EVENT_HANDLER1(void, stop, bool, clear);
|
EVENT_HANDLER1(void, stop, bool, clear);
|
||||||
|
|
||||||
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
|
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data);
|
||||||
EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
|
EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e);
|
||||||
|
|
||||||
//! \handlers
|
//! \handlers
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! \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"
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -131,9 +134,9 @@ private:
|
|||||||
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
|
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
|
||||||
};
|
};
|
||||||
|
|
||||||
void begin();
|
void begin() override;
|
||||||
void run();
|
void run() override;
|
||||||
void end();
|
void end() override;
|
||||||
void key_event(PIKbdListener::KeyEvent key);
|
void key_event(PIKbdListener::KeyEvent key);
|
||||||
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
|
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
|
||||||
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
|
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
|
||||||
@@ -142,9 +145,9 @@ private:
|
|||||||
PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
|
PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
|
||||||
PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
|
PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
|
||||||
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
|
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
|
||||||
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
|
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e) override;
|
||||||
void tileRemovedInternal(PIScreenTile * t);
|
void tileRemovedInternal(PIScreenTile * t) override;
|
||||||
void tileSetFocusInternal(PIScreenTile * t);
|
void tileSetFocusInternal(PIScreenTile * t) override;
|
||||||
|
|
||||||
bool mouse_;
|
bool mouse_;
|
||||||
SystemConsole console;
|
SystemConsole console;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -63,8 +64,8 @@ protected:
|
|||||||
};
|
};
|
||||||
PIVector<Variable> variables;
|
PIVector<Variable> variables;
|
||||||
PIScreenTypes::Alignment alignment;
|
PIScreenTypes::Alignment alignment;
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -31,7 +34,7 @@ class PIScreenDrawer;
|
|||||||
|
|
||||||
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
|
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
|
||||||
friend class PIScreen;
|
friend class PIScreen;
|
||||||
PIOBJECT_SUBCLASS(PIScreenTile, PIObject)
|
PIOBJECT_SUBCLASS(PIScreenTile, PIObject);
|
||||||
public:
|
public:
|
||||||
PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
|
PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
|
||||||
virtual ~PIScreenTile();
|
virtual ~PIScreenTile();
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -28,7 +31,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
|
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
|
||||||
TileSimple(const PIString & n = PIString());
|
TileSimple(const PIString & n = PIString());
|
||||||
@@ -37,15 +40,15 @@ public:
|
|||||||
PIVector<Row> content;
|
PIVector<Row> content;
|
||||||
PIScreenTypes::Alignment alignment;
|
PIScreenTypes::Alignment alignment;
|
||||||
protected:
|
protected:
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TileList;
|
class TileList;
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile);
|
||||||
friend class TileList;
|
friend class TileList;
|
||||||
public:
|
public:
|
||||||
TileScrollBar(const PIString & n = PIString());
|
TileScrollBar(const PIString & n = PIString());
|
||||||
@@ -59,16 +62,16 @@ public:
|
|||||||
int thickness;
|
int thickness;
|
||||||
protected:
|
protected:
|
||||||
void _check();
|
void _check();
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||||
int minimum_, maximum_, value_;
|
int minimum_, maximum_, value_;
|
||||||
PIChar line_char;
|
PIChar line_char;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileList: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileList: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileList, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileList, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
enum SelectionMode {
|
enum SelectionMode {
|
||||||
NoSelection,
|
NoSelection,
|
||||||
@@ -90,19 +93,19 @@ public:
|
|||||||
PISet<int> selected;
|
PISet<int> selected;
|
||||||
int lhei, cur, offset;
|
int lhei, cur, offset;
|
||||||
protected:
|
protected:
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void resizeEvent(int w, int h);
|
void resizeEvent(int w, int h) override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||||
bool wheelEvent(PIKbdListener::WheelEvent we);
|
bool wheelEvent(PIKbdListener::WheelEvent we) override;
|
||||||
TileScrollBar * scroll;
|
TileScrollBar * scroll;
|
||||||
bool mouse_sel;
|
bool mouse_sel;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileButton, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileButton, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
TileButton(const PIString & n = PIString());
|
TileButton(const PIString & n = PIString());
|
||||||
virtual ~TileButton() {}
|
virtual ~TileButton() {}
|
||||||
@@ -112,17 +115,17 @@ public:
|
|||||||
PIScreenTypes::CellFormat format;
|
PIScreenTypes::CellFormat format;
|
||||||
PIString text;
|
PIString text;
|
||||||
protected:
|
protected:
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
TileButtons(const PIString & n = PIString());
|
TileButtons(const PIString & n = PIString());
|
||||||
virtual ~TileButtons() {}
|
virtual ~TileButtons() {}
|
||||||
@@ -134,10 +137,10 @@ public:
|
|||||||
PIVector<Button> content;
|
PIVector<Button> content;
|
||||||
int cur;
|
int cur;
|
||||||
protected:
|
protected:
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||||
struct Rect {
|
struct Rect {
|
||||||
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0),y0(_y0),x1(_x1),y1(_y1) {}
|
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0),y0(_y0),x1(_x1),y1(_y1) {}
|
||||||
int x0,y0,x1,y1;
|
int x0,y0,x1,y1;
|
||||||
@@ -147,7 +150,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
TileCheck(const PIString & n = PIString());
|
TileCheck(const PIString & n = PIString());
|
||||||
virtual ~TileCheck() {}
|
virtual ~TileCheck() {}
|
||||||
@@ -158,15 +161,15 @@ public:
|
|||||||
PIString text;
|
PIString text;
|
||||||
bool toggled;
|
bool toggled;
|
||||||
protected:
|
protected:
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||||
bool mouseEvent(PIKbdListener::MouseEvent me);
|
bool mouseEvent(PIKbdListener::MouseEvent me) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
TileProgress(const PIString & n = PIString());
|
TileProgress(const PIString & n = PIString());
|
||||||
virtual ~TileProgress() {}
|
virtual ~TileProgress() {}
|
||||||
@@ -176,26 +179,26 @@ public:
|
|||||||
double maximum;
|
double maximum;
|
||||||
double value;
|
double value;
|
||||||
protected:
|
protected:
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TilePICout: public TileList {
|
class PIP_CONSOLE_EXPORT TilePICout: public TileList {
|
||||||
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile)
|
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
TilePICout(const PIString & n = PIString());
|
TilePICout(const PIString & n = PIString());
|
||||||
virtual ~TilePICout() {}
|
virtual ~TilePICout() {}
|
||||||
PIScreenTypes::CellFormat format;
|
PIScreenTypes::CellFormat format;
|
||||||
int max_lines;
|
int max_lines;
|
||||||
protected:
|
protected:
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile {
|
class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile {
|
||||||
PIOBJECT_SUBCLASS(TileInput, PIScreenTile)
|
PIOBJECT_SUBCLASS(TileInput, PIScreenTile);
|
||||||
public:
|
public:
|
||||||
TileInput(const PIString & n = PIString());
|
TileInput(const PIString & n = PIString());
|
||||||
virtual ~TileInput() {}
|
virtual ~TileInput() {}
|
||||||
@@ -203,9 +206,9 @@ public:
|
|||||||
PIString text;
|
PIString text;
|
||||||
int max_length;
|
int max_length;
|
||||||
protected:
|
protected:
|
||||||
void sizeHint(int & w, int & h) const;
|
void sizeHint(int & w, int & h) const override;
|
||||||
void drawEvent(PIScreenDrawer * d);
|
void drawEvent(PIScreenDrawer * d) override;
|
||||||
bool keyEvent(PIKbdListener::KeyEvent key);
|
bool keyEvent(PIKbdListener::KeyEvent key) override;
|
||||||
void reserCursor();
|
void reserCursor();
|
||||||
int cur, offset;
|
int cur, offset;
|
||||||
bool inv;
|
bool inv;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -140,11 +143,30 @@ namespace PIScreenTypes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
|
//inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.format.raw_format << v.symbol; return s;}
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
|
//inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.format.raw_format >> v.symbol; return s;}
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Store operator
|
||||||
|
//! \~russian Оператор сохранения
|
||||||
|
BINARY_STREAM_WRITE(PIScreenTypes::Cell) {s << v.format.raw_format << v.symbol; return s;}
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Restore operator
|
||||||
|
//! \~russian Оператор извлечения
|
||||||
|
BINARY_STREAM_READ (PIScreenTypes::Cell) {s >> v.format.raw_format >> v.symbol; return s;}
|
||||||
|
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Store operator
|
||||||
|
//! \~russian Оператор сохранения
|
||||||
|
BINARY_STREAM_WRITE(PIScreenTypes::TileEvent) {s << v.type << v.data; return s;}
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Restore operator
|
||||||
|
//! \~russian Оператор извлечения
|
||||||
|
BINARY_STREAM_READ (PIScreenTypes::TileEvent) {s >> v.type >> v.data; return s;}
|
||||||
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::TileEvent & v) {s << v.type << v.data; return s;}
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::TileEvent & v) {s >> v.type >> v.data; return s;}
|
|
||||||
|
|
||||||
REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent)
|
REGISTER_PIVARIANTSIMPLE(PIScreenTypes::TileEvent)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -30,7 +33,7 @@
|
|||||||
|
|
||||||
class PIP_CONSOLE_EXPORT PITerminal: public PIThread
|
class PIP_CONSOLE_EXPORT PITerminal: public PIThread
|
||||||
{
|
{
|
||||||
PIOBJECT_SUBCLASS(PITerminal, PIThread)
|
PIOBJECT_SUBCLASS(PITerminal, PIThread);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Constructs %PITerminal
|
//! Constructs %PITerminal
|
||||||
@@ -55,7 +58,7 @@ private:
|
|||||||
void readConsole();
|
void readConsole();
|
||||||
void getCursor(int & x, int & y);
|
void getCursor(int & x, int & y);
|
||||||
uchar invertColor(uchar c);
|
uchar invertColor(uchar c);
|
||||||
void run();
|
void run() override;
|
||||||
#ifndef WINDOWS
|
#ifndef WINDOWS
|
||||||
void parseInput(const PIString & s);
|
void parseInput(const PIString & s);
|
||||||
bool isCompleteEscSeq(const PIString & es);
|
bool isCompleteEscSeq(const PIString & es);
|
||||||
|
|||||||
34
libs/main/containers/picontainers.cpp
Normal file
34
libs/main/containers/picontainers.cpp
Normal 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 size_t minAlloc = 64;
|
||||||
|
|
||||||
|
|
||||||
|
size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) {
|
||||||
|
size_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;
|
||||||
|
}
|
||||||
@@ -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 size_t calcMinCountPoT(size_t szof);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class _PIContainerConstants {
|
||||||
|
public:
|
||||||
|
static size_t minCountPoT() {static size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T)); return ret;}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
# define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)
|
//! \brief
|
||||||
|
//! \~english Template reverse wrapper over any container
|
||||||
|
//! \~russian Шаблонная функция обертки любого контейнера для обратного доступа через итераторы
|
||||||
|
template <typename C> _PIReverseWrapper<C> PIReverseWrap(C & c) {return _PIReverseWrapper<C>(c);}
|
||||||
|
template <typename C> _PIReverseWrapper<C> PIReverseWrap(const C & c) {return _PIReverseWrapper<C>(c);}
|
||||||
|
|
||||||
# define piForeach(i,c) for(i : c)
|
|
||||||
# define piForeachC(i,c) for(const i : c)
|
|
||||||
# define piForeachR(i,c) for(i : _reverse_wrap(c))
|
|
||||||
# define piForeachRC(i,c) for(const i : _reverse_wrap(c))
|
|
||||||
|
|
||||||
# define piForeachCR piForeachRC
|
//! \brief
|
||||||
|
//! \~english Macro for short replacement of standart "for"
|
||||||
|
//! \~russian Макрос для короткой записи стандартного цикла "for"
|
||||||
|
//! \~\param c
|
||||||
|
//! \~english Iteration times in loop
|
||||||
|
//! \~russian Количество итераций цикла
|
||||||
|
#define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)
|
||||||
|
|
||||||
#endif // DOXYGEN
|
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Macro for iterate any container
|
||||||
|
//! \~russian Макрос для перебора любых контейнеров
|
||||||
|
//! \~\deprecated
|
||||||
|
//! \~english Deprecated, using only for backward compatibility. Use
|
||||||
|
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~russian Устарело, используется только для обратной совместимости. Используйте
|
||||||
|
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Get read/write access to each element of container.
|
||||||
|
//! Iterating in forward direction.
|
||||||
|
//! Example of using:
|
||||||
|
//! \~russian Перебор всех элементов контейнера с доступом на чтение и запись.
|
||||||
|
//! Перебор осуществляется в прямом порядке.
|
||||||
|
//! Пример использования:
|
||||||
|
//! \~\code
|
||||||
|
//! PIVector<int> vec;
|
||||||
|
//! vec << 1 << 2 << 3;
|
||||||
|
//! piForeach(int & i, vec) piCout << i;
|
||||||
|
//! // 1
|
||||||
|
//! // 2
|
||||||
|
//! // 3
|
||||||
|
//! piForeach(int & i, vec) i++;
|
||||||
|
//! piForeach(int & i, vec) piCout << i;
|
||||||
|
//! // 2
|
||||||
|
//! // 3
|
||||||
|
//! // 4
|
||||||
|
//! \endcode
|
||||||
|
//! \sa \a piForeachC, \a piForeachR, \a piForeachRC
|
||||||
|
#define piForeach(i, c) for(i : c)
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Macro for iterate any container
|
||||||
|
//! \~russian Макрос для перебора любых контейнеров
|
||||||
|
//! \~\deprecated
|
||||||
|
//! \~english Deprecated, using only for backward compatibility. Use
|
||||||
|
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~russian Устарело, используется только для обратной совместимости. Используйте
|
||||||
|
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Get read only access to each element of container.
|
||||||
|
//! Iterating in forward direction.
|
||||||
|
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
|
||||||
|
//! Перебор осуществляется в прямом порядке.
|
||||||
|
//! \~ \sa \a piForeach, \a piForeachR, \a piForeachRC
|
||||||
|
#define piForeachC(i, c) for(const i : c)
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Macro for iterate any container
|
||||||
|
//! \~russian Макрос для перебора любых контейнеров
|
||||||
|
//! \~\deprecated
|
||||||
|
//! \~english Deprecated, using only for backward compatibility. Use
|
||||||
|
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~russian Устарело, используется только для обратной совместимости. Используйте
|
||||||
|
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Get read/write access to each element of container.
|
||||||
|
//! Iterating in backward direction.
|
||||||
|
//! \~russian Перебор всех элементов контейнера с доступом на чтение и запись.
|
||||||
|
//! Перебор осуществляется в обратном порядке.
|
||||||
|
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachRC
|
||||||
|
#define piForeachR(i, c) for(i : PIReverseWrap(c))
|
||||||
|
|
||||||
|
//! \brief
|
||||||
|
//! \~english Macro for iterate any container
|
||||||
|
//! \~russian Макрос для перебора любых контейнеров
|
||||||
|
//! \~\deprecated
|
||||||
|
//! \~english Deprecated, using only for backward compatibility. Use
|
||||||
|
//! [C++ Range-based for loop](https://en.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~russian Устарело, используется только для обратной совместимости. Используйте
|
||||||
|
//! [C++ Range-based for loop](https://ru.cppreference.com/w/cpp/language/range-for).
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Get read only access to each element of container.
|
||||||
|
//! Iterating in backward direction. Also has alias **piForeachCR**
|
||||||
|
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
|
||||||
|
//! Перебор осуществляется в обратном порядке. Также можно писать **piForeachCR**
|
||||||
|
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachR
|
||||||
|
#define piForeachRC(i, c) for(const i : PIReverseWrap(c))
|
||||||
|
#define piForeachCR piForeachRC
|
||||||
|
|
||||||
|
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english Reshape order enum for reshape() function.
|
||||||
|
//! \~russian Порядок обхода для функции изменения размерности reshape().
|
||||||
|
//! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape()
|
||||||
|
enum ReshapeOrder {
|
||||||
|
ReshapeByRow /*! \~english Traversing elements by line, just as they stay in memory \~russian Обход элементов построчно, так же как они находятся в памяти */,
|
||||||
|
ReshapeByColumn /*! \~english Traversing elements by column \~russian Обход элементов по столбцам */,
|
||||||
|
};
|
||||||
|
|
||||||
#endif // PICONTAINERS_H
|
#endif // PICONTAINERS_H
|
||||||
|
|||||||
@@ -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.
|
||||||
|
//!
|
||||||
|
//! 
|
||||||
|
//!
|
||||||
|
//! 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(), поэтому цикл никогда не выполнится.
|
||||||
|
//!
|
||||||
|
//! 
|
||||||
|
//!
|
||||||
|
//! В следующей таблице подводится итог 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
|
||||||
|
|||||||
@@ -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 
|
||||||
|
//!
|
||||||
|
//! \~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 
|
||||||
|
//!
|
||||||
|
//! \~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 
|
||||||
|
//!
|
||||||
|
//! \~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 
|
||||||
|
//!
|
||||||
|
//! \~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 (size_t i = pid_start; i < pid_start + pid_size; ++i) {
|
||||||
|
if (test(pid_data[i])) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Tests whether all elements in the array passes the test
|
||||||
|
//! implemented by the provided function `test`.
|
||||||
|
//! \~russian Проверяет, удовлетворяют ли все элементы массива условию,
|
||||||
|
//! заданному в передаваемой функции `test`.
|
||||||
|
//! \~\return
|
||||||
|
//! \~english **true** if, in the array,
|
||||||
|
//! it finds an element for which the provided function returns **true**;
|
||||||
|
//! otherwise it returns **false**. Always returns **true** if is empty.
|
||||||
|
//! \~russian **true** если для всех элементов передаваемая функция возвращает **true**,
|
||||||
|
//! в остальных случаях **false**.
|
||||||
|
//! Метод возвращает **true** при любом условии для пустого массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\code
|
||||||
|
//! PIDeque<int> v{1, 2, 8, 9};
|
||||||
|
//! piCout << v.every([](int e){return e % 2 == 0;}); // false
|
||||||
|
//! piCout << v.every([](int e){return e > 0;}); // true
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a any(), \a contains(), \a entries(), \a forEach()
|
||||||
|
inline bool every(std::function<bool(const T & e)> test) const {
|
||||||
|
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
|
||||||
|
if (!test(pid_data[i])) return false;
|
||||||
|
}
|
||||||
return true;
|
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 (size_t i = pid_start + size_t(start); i < pid_start + 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, ssize_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 (size_t i = pid_start + size_t(start); i < pid_start + 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, ssize_t start = 0) const {
|
||||||
|
int ec = 0;
|
||||||
|
if (start < 0) {
|
||||||
|
start = pid_size + start;
|
||||||
|
if (start < 0) start = 0;
|
||||||
|
}
|
||||||
|
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||||
|
if (test(pid_data[i])) ++ec;
|
||||||
|
}
|
||||||
|
return ec;
|
||||||
}
|
}
|
||||||
inline ssize_t lastIndexOf(const T & v) const {
|
|
||||||
for (ssize_t i = pid_start + (ssize_t)pid_size - 1; i >= pid_start; --i)
|
//! \~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.
|
||||||
return i - pid_start;
|
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
|
||||||
|
//! может быть найден в массиве или `-1`, если такого индекса нет.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Optional argument `start` - the position in this array at which to begin searching.
|
||||||
|
//! If the index is greater than or equal to the array's size,
|
||||||
|
//! `-1` is returned, which means the array will not be searched.
|
||||||
|
//! If the provided index value is a negative number,
|
||||||
|
//! it is taken as the offset from the end of the array.
|
||||||
|
//! Note: if the provided index is negative,
|
||||||
|
//! the array is still searched from front to back.
|
||||||
|
//! Default: 0 (entire array is searched).
|
||||||
|
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||||
|
//! Если индекс больше или равен длине массива,
|
||||||
|
//! возвращается `-1`, что означает, что массив даже не просматривается.
|
||||||
|
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||||
|
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||||
|
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||||
|
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||||
|
//! \~\code
|
||||||
|
//! PIDeque<int> v{2, 5, 9};
|
||||||
|
//! piCout << v.indexOf(2); // 0
|
||||||
|
//! piCout << v.indexOf(7); // -1
|
||||||
|
//! piCout << v.indexOf(9, 2); // 2
|
||||||
|
//! piCout << v.indexOf(2, -1); // -1
|
||||||
|
//! piCout << v.indexOf(2, -3); // 0
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a indexWhere(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
|
||||||
|
inline ssize_t indexOf(const T & e, ssize_t start = 0) const {
|
||||||
|
if (start < 0) {
|
||||||
|
start = pid_size + start;
|
||||||
|
if (start < 0) start = 0;
|
||||||
|
}
|
||||||
|
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||||
|
if (e == pid_data[i]) {
|
||||||
|
return ssize_t(i) - pid_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
return -1;
|
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, ssize_t start = 0) const {
|
||||||
|
if (start < 0) {
|
||||||
|
start = pid_size + start;
|
||||||
|
if (start < 0) start = 0;
|
||||||
|
}
|
||||||
|
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
|
||||||
|
if (test(pid_data[i])) {
|
||||||
|
return ssize_t(i) - pid_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 (size_t i = pid_start + size_t(start); i >= pid_start; --i) {
|
||||||
|
if (e == pid_data[i]) {
|
||||||
|
return ssize_t(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 (size_t i = pid_start + size_t(start); i >= pid_start; --i) {
|
||||||
|
if (test(pid_data[i])) {
|
||||||
|
return ssize_t(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 = ssize_t(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,169 +1439,849 @@ 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);
|
||||||
piSwap<size_t>(pid_rsize, other.pid_rsize);
|
piSwap<size_t>(pid_rsize, other.pid_rsize);
|
||||||
piSwap<ssize_t>(pid_start, other.pid_start);
|
piSwap<size_t>(pid_start, other.pid_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef int (*CompareFunc)(const T * , const T * );
|
//! \~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;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PIDeque<T> & enlarge(llong pid_size) {
|
//! \~english Sorts the elements in non-descending order.
|
||||||
llong ns = size_s() + pid_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
|
||||||
|
//! 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(ssize_t add_size, const T & e = T()) {
|
||||||
|
ssize_t 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 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 (size_t i = 0; i < 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 (size_t i = 0; i < 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 push_front(init_list);}
|
||||||
|
|
||||||
|
//! \~english Remove one element from the end of the array.
|
||||||
|
//! \~russian Удаляет один элемент с конца массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Deleting an element from the end is very fast
|
||||||
|
//! and does not depend on the size of the array.
|
||||||
|
//! \~russian Удаление элемента с конца выполняется очень быстро
|
||||||
|
//! и не зависит от размера массива.
|
||||||
|
//! \~\code
|
||||||
|
//! PIDeque<int> v{1, 2, 3};
|
||||||
|
//! v.pop_back();
|
||||||
|
//! piCout << v; // {1, 2}
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a pop_front(), \a take_back(), \a take_front()
|
||||||
|
inline PIDeque<T> & pop_back() {
|
||||||
|
if (pid_size == 0) return *this;
|
||||||
|
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;
|
}
|
||||||
|
size_t t = _PIContainerConstants<T>::minCountPoT();
|
||||||
|
size_t s_ = s - 1;
|
||||||
while (s_ >> t)
|
while (s_ >> t)
|
||||||
++t;
|
++t;
|
||||||
return (1 << t);
|
return (1 << t);
|
||||||
@@ -577,8 +2307,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,11 +2346,11 @@ 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 < (pid_size + pid_size) || ssize_t(pid_start) > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) {
|
||||||
ssize_t ns = (pid_rsize - pid_size) / 2;
|
size_t ns = (pid_rsize - pid_size) / 2;
|
||||||
if (pid_start != ns) {
|
if (pid_start != ns) {
|
||||||
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||||
pid_start = ns;
|
pid_start = ns;
|
||||||
@@ -627,18 +2358,17 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ssize_t ns = (pid_rsize - pid_size) / 2;
|
size_t ns = (pid_rsize - pid_size) / 2;
|
||||||
if (pid_start != ns) {
|
if (pid_start != ns) {
|
||||||
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
memmove((void*)(pid_data + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||||
pid_start = ns;
|
pid_start = ns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,19 +2376,26 @@ 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 (ssize_t(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;
|
size_t ns = pid_start + as - pid_rsize;
|
||||||
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
|
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
|
||||||
if (pid_rsize > 0 && pid_data != 0) {
|
if (pid_rsize > 0 && pid_data != 0) {
|
||||||
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
|
||||||
@@ -670,37 +2407,51 @@ 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;
|
||||||
size_t pid_size, pid_rsize;
|
size_t pid_size;
|
||||||
ssize_t pid_start;
|
size_t pid_rsize;
|
||||||
|
size_t pid_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#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) {
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline PICout operator <<(PICout s, const PIDeque<T> & v) {
|
|
||||||
s.space();
|
|
||||||
s.setControl(0, true);
|
|
||||||
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();
|
return s;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//! \relatesalso PICout
|
||||||
|
//! \~english Output operator to \a PICout
|
||||||
|
//! \~russian Оператор вывода в \a PICout
|
||||||
|
template<typename T>
|
||||||
|
inline PICout operator <<(PICout s, const PIDeque<T> & v) {
|
||||||
|
s.space();
|
||||||
|
s.saveAndSetControls(0);
|
||||||
|
s << "{";
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) {
|
||||||
|
s << v[i];
|
||||||
|
if (i < v.size() - 1) s << ", ";
|
||||||
|
}
|
||||||
|
s << "}";
|
||||||
|
s.restoreControls();
|
||||||
return s;
|
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
|
||||||
|
|||||||
@@ -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,100 @@
|
|||||||
* \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 +110,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 +167,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.
|
||||||
|
|
||||||
* */
|
* */
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
/*! @file pimap.h
|
//! \addtogroup Containers
|
||||||
* @brief Associative array with custom types of key and value
|
//! \{
|
||||||
*
|
//! \file pideque.h
|
||||||
* This file declares PIMap
|
//! \brief
|
||||||
*/
|
//! \~english Declares \a PIMap
|
||||||
|
//! \~russian Объявление \a PIMap
|
||||||
|
//! \~\authors
|
||||||
|
//! \~english
|
||||||
|
//! Ivan Pelipenko peri4ko@yandex.ru;
|
||||||
|
//! Andrey Bychkov work.a.b@yandex.ru;
|
||||||
|
//! \~russian
|
||||||
|
//! Иван Пелипенко peri4ko@yandex.ru;
|
||||||
|
//! Андрей Бычков work.a.b@yandex.ru;
|
||||||
|
//! \~\}
|
||||||
/*
|
/*
|
||||||
PIP - Platform Independent Primitives
|
PIP - Platform Independent Primitives
|
||||||
Associative array with custom types of key and value
|
Associative array with custom types of key and value
|
||||||
@@ -30,56 +39,85 @@
|
|||||||
#include "pipair.h"
|
#include "pipair.h"
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template <typename Key, typename T> class PIMapIteratorConst;
|
||||||
void piQuickSort(T * a, ssize_t N) {
|
template <typename Key, typename T> class PIMapIteratorConstReverse;
|
||||||
if (N < 1) return;
|
template <typename Key, typename T> class PIMapIterator;
|
||||||
if (N < 46) {
|
template <typename Key, typename T> class PIMapIteratorReverse;
|
||||||
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>
|
|
||||||
class PIMapIterator;
|
|
||||||
|
|
||||||
|
|
||||||
|
//! \addtogroup Containers
|
||||||
|
//! \{
|
||||||
|
//! \class PIMap
|
||||||
|
//! \brief
|
||||||
|
//! \~english Associative array.
|
||||||
|
//! \~russian Словарь.
|
||||||
|
//! \~\}
|
||||||
|
//! \details
|
||||||
|
//! \~english
|
||||||
|
//! A collection of key/value pairs, from which you retrieve a value using its associated key.
|
||||||
|
//! There is a finite number of keys in the map, and each key has exactly one value associated with it.
|
||||||
|
//! \a value() returns value for key and leave map
|
||||||
|
//! unchaged in any case. \a operator [] create entry in map if
|
||||||
|
//! there is no entry for given key. You can retrieve all
|
||||||
|
//! keys by method \a keys() and all values by methos \a values().
|
||||||
|
//! To iterate all entries use class PIMapIterator, or methods
|
||||||
|
//! \a makeIterator() and \a makeReverseIterator().
|
||||||
|
//! A key in the Map may only occur once.
|
||||||
|
//! \~russian
|
||||||
|
//! Словари, в принципе, похожи на обычные, используемые в повседневной жизни.
|
||||||
|
//! Они хранят элементы одного и того же типа, индексируемые ключевыми значениями.
|
||||||
|
//! Достоинство словаря в том, что он позволяет быстро получать значение,
|
||||||
|
//! ассоциированное с заданным ключом.
|
||||||
|
//! Ключи должны быть уникальными.
|
||||||
|
//! Элемент
|
||||||
|
//! В контейнеры этого типа заносятся элементы вместе с ключами,
|
||||||
|
//! по которым их можно найти, которыми могут выступать значения любого типа.
|
||||||
|
//! \a operator [] позволяет получить доступ к элементу по ключу,
|
||||||
|
//! и если такого эелемента не было, то он будет создан.
|
||||||
template <typename Key, typename T>
|
template <typename Key, typename T>
|
||||||
class PIMap {
|
class PIMap {
|
||||||
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIMap<Key1, T1> & v);
|
template <typename Key1, typename T1> friend class PIMapIteratorConst;
|
||||||
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
|
template <typename Key1, typename T1> friend class PIMapIteratorConstReverse;
|
||||||
template <typename Key1, typename T1> friend class PIMapIterator;
|
template <typename Key1, typename T1> friend class PIMapIterator;
|
||||||
|
template <typename Key1, typename T1> friend class PIMapIteratorReverse;
|
||||||
|
template <typename P, typename Key1, typename T1>
|
||||||
|
friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMap<Key1, T1> & v);
|
||||||
|
template <typename P, typename Key1, typename T1>
|
||||||
|
friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMap<Key1, T1> & v);
|
||||||
public:
|
public:
|
||||||
PIMap() {;}
|
typedef T mapped_type;
|
||||||
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
typedef Key key_type;
|
||||||
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
|
typedef PIPair<Key, T> value_type;
|
||||||
virtual ~PIMap() {;}
|
|
||||||
|
|
||||||
|
//! \~english Constructs an empty map.
|
||||||
|
//! \~russian Создает пустой словарь.
|
||||||
|
PIMap() {}
|
||||||
|
|
||||||
|
//! \~english Copy constructor.
|
||||||
|
//! \~russian Копирующий конструктор.
|
||||||
|
PIMap(const PIMap<Key, T> & other) {*this = other;}
|
||||||
|
|
||||||
|
//! \~english Move constructor.
|
||||||
|
//! \~russian Перемещающий конструктор.
|
||||||
|
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
|
||||||
|
|
||||||
|
//! \~english Contructs map from
|
||||||
|
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
|
||||||
|
//! \~russian Создает словарь из
|
||||||
|
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
|
||||||
|
//! \~\details
|
||||||
|
//! \~\code
|
||||||
|
//! PIMap <int, PIString> m{{1, "a"}, {2, "b"}};
|
||||||
|
//! piCout << m; // {1, 2, 3}
|
||||||
|
//! \endcode
|
||||||
|
PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
|
||||||
|
for (auto i: init_list) {
|
||||||
|
insert(std::get<0>(i), std::get<1>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Assign operator.
|
||||||
|
//! \~russian Оператор присваивания.
|
||||||
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();
|
||||||
@@ -88,14 +126,12 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \~english Assign move operator.
|
||||||
|
//! \~russian Оператор перемещающего присваивания.
|
||||||
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
|
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
|
||||||
swap(other);
|
swap(other);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef T mapped_type;
|
|
||||||
typedef Key key_type;
|
|
||||||
typedef PIPair<Key, T> value_type;
|
|
||||||
|
|
||||||
class iterator {
|
class iterator {
|
||||||
friend class PIMap<Key, T>;
|
friend class PIMap<Key, T>;
|
||||||
@@ -104,9 +140,12 @@ public:
|
|||||||
const PIMap<Key, T> * parent;
|
const PIMap<Key, T> * parent;
|
||||||
ssize_t pos;
|
ssize_t pos;
|
||||||
public:
|
public:
|
||||||
iterator(): parent(0), pos(0) {}
|
iterator(): parent(nullptr), pos(0) {}
|
||||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||||
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;}
|
||||||
@@ -122,9 +161,12 @@ public:
|
|||||||
const PIMap<Key, T> * parent;
|
const PIMap<Key, T> * parent;
|
||||||
ssize_t pos;
|
ssize_t pos;
|
||||||
public:
|
public:
|
||||||
reverse_iterator(): parent(0), pos(0) {}
|
reverse_iterator(): parent(nullptr), pos(0) {}
|
||||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||||
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;}
|
||||||
@@ -140,9 +182,8 @@ public:
|
|||||||
const PIMap<Key, T> * parent;
|
const PIMap<Key, T> * parent;
|
||||||
ssize_t pos;
|
ssize_t pos;
|
||||||
public:
|
public:
|
||||||
const_iterator(): parent(0), pos(0) {}
|
const_iterator(): parent(nullptr), pos(0) {}
|
||||||
const value_type operator *() const {return parent->_pair(pos);}
|
const value_type operator *() const {return parent->_pair(pos);}
|
||||||
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
|
||||||
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
|
||||||
const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
|
||||||
void operator ++() {++pos;}
|
void operator ++() {++pos;}
|
||||||
@@ -151,7 +192,6 @@ public:
|
|||||||
void operator --(int) {--pos;}
|
void operator --(int) {--pos;}
|
||||||
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
|
||||||
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
|
||||||
mutable value_type cval;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class const_reverse_iterator {
|
class const_reverse_iterator {
|
||||||
@@ -161,38 +201,62 @@ public:
|
|||||||
const PIMap<Key, T> * parent;
|
const PIMap<Key, T> * parent;
|
||||||
ssize_t pos;
|
ssize_t pos;
|
||||||
public:
|
public:
|
||||||
const_reverse_iterator(): parent(0), pos(0) {}
|
const_reverse_iterator(): parent(nullptr), pos(0) {}
|
||||||
const value_type operator *() const {return parent->_pair(pos);}
|
const value_type operator *() const {return parent->_pair(pos);}
|
||||||
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
|
|
||||||
void operator ++() {--pos;}
|
void operator ++() {--pos;}
|
||||||
void operator ++(int) {--pos;}
|
void operator ++(int) {--pos;}
|
||||||
void operator --() {++pos;}
|
void operator --() {++pos;}
|
||||||
void operator --(int) {++pos;}
|
void operator --(int) {++pos;}
|
||||||
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
|
||||||
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
|
||||||
mutable value_type cval;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
iterator begin() {return iterator(this, 0);}
|
iterator begin() {return iterator(this, 0);}
|
||||||
|
|
||||||
iterator end() {return iterator(this, size());}
|
iterator end() {return iterator(this, size());}
|
||||||
|
|
||||||
const_iterator begin() const {return const_iterator(this, 0);}
|
const_iterator begin() const {return const_iterator(this, 0);}
|
||||||
|
|
||||||
const_iterator end() const {return const_iterator(this, size());}
|
const_iterator end() const {return const_iterator(this, size());}
|
||||||
|
|
||||||
const_iterator constBegin() const {return const_iterator(this, 0);}
|
const_iterator constBegin() const {return const_iterator(this, 0);}
|
||||||
|
|
||||||
const_iterator constEnd() const {return const_iterator(this, size());}
|
const_iterator constEnd() const {return const_iterator(this, size());}
|
||||||
|
|
||||||
reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
|
reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
|
||||||
|
|
||||||
reverse_iterator rend() {return reverse_iterator(this, -1);}
|
reverse_iterator rend() {return reverse_iterator(this, -1);}
|
||||||
|
|
||||||
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
|
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
|
||||||
|
|
||||||
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
|
||||||
|
|
||||||
const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
|
const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
|
||||||
|
|
||||||
const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}
|
const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}
|
||||||
|
|
||||||
PIMapIterator<Key, T> makeIterator() const {return PIMapIterator<Key, T>(*this);}
|
//! \relatesalso PIMapIteratorConst
|
||||||
PIMapIterator<Key, T> makeReverseIterator() const {return PIMapIterator<Key, T>(*this, true);}
|
PIMapIteratorConst<Key, T> makeIterator() const {return PIMapIteratorConst<Key, T>(*this);}
|
||||||
|
|
||||||
|
//! \relatesalso PIMapIterator
|
||||||
|
PIMapIterator<Key, T> makeIterator() {return PIMapIterator<Key, T>(*this);}
|
||||||
|
|
||||||
|
//! \relatesalso PIMapIteratorConstReverse
|
||||||
|
PIMapIteratorConstReverse<Key, T> makeReverseIterator() const {return PIMapIteratorConstReverse<Key, T>(*this);}
|
||||||
|
|
||||||
|
//! \relatesalso PIMapIteratorReverse
|
||||||
|
PIMapIteratorReverse<Key, T> makeReverseIterator() {return PIMapIteratorReverse<Key, T>(*this);}
|
||||||
|
|
||||||
size_t size() const {return pim_content.size();}
|
size_t size() const {return pim_content.size();}
|
||||||
|
|
||||||
int size_s() const {return pim_content.size_s();}
|
int size_s() const {return pim_content.size_s();}
|
||||||
|
|
||||||
size_t length() const {return pim_content.size();}
|
size_t length() const {return pim_content.size();}
|
||||||
|
|
||||||
bool isEmpty() const {return (pim_content.size() == 0);}
|
bool isEmpty() const {return (pim_content.size() == 0);}
|
||||||
|
|
||||||
|
bool isNotEmpty() const {return (pim_content.size() > 0);}
|
||||||
|
|
||||||
T & operator [](const Key & key) {
|
T & operator [](const Key & key) {
|
||||||
bool f(false);
|
bool f(false);
|
||||||
@@ -202,29 +266,85 @@ public:
|
|||||||
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
|
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
|
||||||
return pim_content.back();
|
return pim_content.back();
|
||||||
}
|
}
|
||||||
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();}
|
T at(const Key & key) const {return value(key);}
|
||||||
const T at(const Key & key) const {return (*this)[key];}
|
|
||||||
|
T take(const Key & key) const {
|
||||||
|
bool f(false);
|
||||||
|
ssize_t i = _find(key, f);
|
||||||
|
if (!f) return T();
|
||||||
|
T ret(pim_content[pim_index[i].index]);
|
||||||
|
_remove(i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
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;}
|
insert(other.pim_index[0].key, other.pim_content[0]);
|
||||||
for (int i = 0; i < other.pim_index.size_s(); ++i)
|
return *this;
|
||||||
|
}
|
||||||
|
if (other.size() == 2) {
|
||||||
|
insert(other.pim_index[0].key, other.pim_content[0]);
|
||||||
|
insert(other.pim_index[1].key, other.pim_content[1]);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < other.pim_index.size_s(); ++i) {
|
||||||
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
|
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
|
||||||
|
}
|
||||||
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 {
|
||||||
bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content || pim_index != t.pim_index);}
|
return (pim_content == t.pim_content && pim_index == t.pim_index);
|
||||||
bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
|
}
|
||||||
|
bool operator !=(const PIMap<Key, T> & t) const {
|
||||||
|
return (pim_content != t.pim_content || pim_index != t.pim_index);
|
||||||
|
}
|
||||||
|
bool contains(const Key & key) const {
|
||||||
|
bool f(false); _find(key, f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size); pim_index.reserve(new_size); return *this;}
|
bool containsValue(const T & value) const {
|
||||||
|
return pim_content.contains(value);
|
||||||
|
}
|
||||||
|
|
||||||
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> & reserve(size_t new_size) {
|
||||||
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
|
pim_content.reserve(new_size);
|
||||||
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
|
pim_index.reserve(new_size);
|
||||||
PIMap<Key, T> & clear() {pim_content.clear(); pim_index.clear(); return *this;}
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIMap<Key, T> & remove(const Key & key) {
|
||||||
|
bool f(false);
|
||||||
|
ssize_t i = _find(key, f);
|
||||||
|
if (f) _remove(i);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIMap<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> test) {
|
||||||
|
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||||
|
if (pim_index[i].key, pim_content[pim_index[i].index]) {
|
||||||
|
_remove(i);
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PIMap<Key, T> & erase(const Key & key) {return remove(key);}
|
||||||
|
|
||||||
|
PIMap<Key, T> & clear() {
|
||||||
|
pim_content.clear();
|
||||||
|
pim_index.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);
|
||||||
@@ -234,7 +354,6 @@ public:
|
|||||||
PIMap<Key, T> & insert(const Key & key, const T & value) {
|
PIMap<Key, T> & insert(const Key & key, const T & value) {
|
||||||
bool f(false);
|
bool f(false);
|
||||||
ssize_t i = _find(key, f);
|
ssize_t i = _find(key, f);
|
||||||
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
|
|
||||||
if (f) {
|
if (f) {
|
||||||
pim_content[pim_index[i].index] = value;
|
pim_content[pim_index[i].index] = value;
|
||||||
} else {
|
} else {
|
||||||
@@ -246,7 +365,6 @@ public:
|
|||||||
PIMap<Key, T> & insert(const Key & key, T && value) {
|
PIMap<Key, T> & insert(const Key & key, T && value) {
|
||||||
bool f(false);
|
bool f(false);
|
||||||
ssize_t i = _find(key, f);
|
ssize_t i = _find(key, f);
|
||||||
//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[pim_index[i].index] = std::move(value);
|
||||||
} else {
|
} else {
|
||||||
@@ -255,28 +373,85 @@ public:
|
|||||||
}
|
}
|
||||||
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];}
|
PIMap<Key, T> & insert(const PIPair<Key, T> & pair) {
|
||||||
|
bool f(false);
|
||||||
|
ssize_t i = _find(pair.first, f);
|
||||||
|
if (f) {
|
||||||
|
pim_content[pim_index[i].index] = pair.second;
|
||||||
|
} else {
|
||||||
|
pim_content.push_back(pair.second);
|
||||||
|
pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
|
||||||
|
bool f(false);
|
||||||
|
Key k(std::move(pair.first));
|
||||||
|
ssize_t i = _find(k, f);
|
||||||
|
if (f) {
|
||||||
|
pim_content[pim_index[i].index] = std::move(pair.second);
|
||||||
|
} else {
|
||||||
|
pim_content.push_back(std::move(pair.second));
|
||||||
|
pim_index.insert(i, MapIndex(k, pim_content.size() - 1));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T value(const Key & key, const T & default_ = T()) const {
|
||||||
|
bool f(false);
|
||||||
|
ssize_t i = _find(key, f);
|
||||||
|
if (!f) return default_;
|
||||||
|
return pim_content[pim_index[i].index];
|
||||||
|
}
|
||||||
|
|
||||||
PIVector<T> values() const {return pim_content;}
|
PIVector<T> values() const {return pim_content;}
|
||||||
Key key(const T & value_, const Key & default_ = Key()) const {for (int i = 0; i < pim_index.size_s(); ++i) if (pim_content[pim_index[i].index] == value_) return pim_index[i].key; return default_;}
|
|
||||||
|
Key key(const T & value_, const Key & default_ = Key()) const {
|
||||||
|
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||||
|
if (pim_content[pim_index[i].index] == value_) {
|
||||||
|
return pim_index[i].key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default_;
|
||||||
|
}
|
||||||
|
|
||||||
PIVector<Key> keys() const {
|
PIVector<Key> keys() const {
|
||||||
PIVector<Key> ret;
|
PIVector<Key> ret;
|
||||||
for (int i = 0; i < pim_index.size_s(); ++i)
|
ret.reserve(pim_index.size());
|
||||||
|
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||||
ret << pim_index[i].key;
|
ret << pim_index[i].key;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void forEach(std::function<void(const Key & key, const T & value)> f) const {
|
||||||
|
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||||
|
f(pim_index[i].key, pim_content[pim_index[i].index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Key2, typename T2>
|
||||||
|
inline PIMap<Key2, T2> map(std::function<PIPair<Key2, T2>(const Key & key, const T & value)> f) const {
|
||||||
|
PIMap<Key2, T2> ret; ret.reserve(size());
|
||||||
|
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||||
|
ret.insert(f(pim_index[i].key, pim_content[pim_index[i].index]));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ST>
|
||||||
|
inline PIVector<ST> map(std::function<ST(const Key & key, const T & value)> f) const {
|
||||||
|
PIVector<ST> ret; ret.reserve(size());
|
||||||
|
for (int i = 0; i < pim_index.size_s(); ++i) {
|
||||||
|
ret << f(pim_index[i].key, pim_content[pim_index[i].index]);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump() {
|
private:
|
||||||
piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:";
|
|
||||||
for (size_t i = 0; i < pim_content.size(); ++i)
|
|
||||||
piCout << PICoutManipulators::Tab << i << ":" << pim_content[i];
|
|
||||||
piCout << "index:";
|
|
||||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
|
||||||
piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
struct MapIndex {
|
struct MapIndex {
|
||||||
MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;}
|
MapIndex(const Key & k = Key(), size_t i = 0): key(k), index(i) {}
|
||||||
|
MapIndex(Key && k, size_t i = 0): key(std::move(k)), index(i) {}
|
||||||
Key key;
|
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;}
|
||||||
@@ -284,10 +459,13 @@ protected:
|
|||||||
bool operator <(const MapIndex & s) const {return key < s.key;}
|
bool operator <(const MapIndex & s) const {return key < s.key;}
|
||||||
bool operator >(const MapIndex & s) const {return key > s.key;}
|
bool operator >(const MapIndex & s) const {return key > s.key;}
|
||||||
};
|
};
|
||||||
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
|
||||||
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
|
||||||
|
|
||||||
ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
|
template <typename P, typename Key1, typename T1>
|
||||||
|
friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||||
|
template <typename P, typename Key1, typename T1>
|
||||||
|
friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -298,83 +476,353 @@ protected:
|
|||||||
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_index.isEmpty()) {
|
||||||
found = false;
|
found = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return binarySearch(0, pim_index.size_s() - 1, k, found);
|
return _binarySearch(0, pim_index.size_s() - 1, k, found);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _remove(ssize_t index) {
|
void _remove(ssize_t index) {
|
||||||
//if (index >= pim_index.size()) return;
|
|
||||||
size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
|
size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
|
||||||
pim_index.remove(index);
|
pim_index.remove(index);
|
||||||
for (size_t i = 0; i < pim_index.size(); ++i)
|
for (size_t i = 0; i < pim_index.size(); ++i) {
|
||||||
if (pim_index[i].index == bi) {
|
if (pim_index[i].index == bi) {
|
||||||
pim_index[i].index = ci;
|
pim_index[i].index = ci;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
piSwap<T>(pim_content[ci], pim_content.back());
|
piSwap<T>(pim_content[ci], pim_content.back());
|
||||||
pim_content.resize(pim_index.size());
|
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_index.size_s()) return value_type();
|
||||||
return value_type();
|
|
||||||
//piCout << "_pair" << index << pim_index[index].index;
|
|
||||||
return value_type(pim_index[index].key, pim_content[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_index[index].key;}
|
||||||
|
|
||||||
|
const Key & _key(ssize_t index) const {return pim_index[index].key;}
|
||||||
|
|
||||||
T & _value(ssize_t index) {return pim_content[pim_index[index].index];}
|
T & _value(ssize_t index) {return pim_content[pim_index[index].index];}
|
||||||
|
|
||||||
|
const T & _value(ssize_t index) const {return pim_content[pim_index[index].index];}
|
||||||
|
|
||||||
|
|
||||||
PIVector<T> pim_content;
|
PIVector<T> pim_content;
|
||||||
PIDeque<MapIndex> pim_index;
|
PIDeque<MapIndex> pim_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \addtogroup Containers
|
||||||
|
//! \{
|
||||||
|
//! \class PIMapIteratorConst
|
||||||
|
//! \brief
|
||||||
|
//! \~english Java-style iterator for \a PIMap.
|
||||||
|
//! \~russian Итератор Java стиля для \a PIMap.
|
||||||
|
//! \~\}
|
||||||
|
//! \details
|
||||||
|
//! \~english
|
||||||
|
//! This class used to easy serial access keys and values in PIMap with read only permitions.
|
||||||
|
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
|
||||||
|
//! \~russian
|
||||||
|
//! Этот класс используется для удобного перебора ключей и значений всего словаря только для чтения.
|
||||||
|
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
|
||||||
|
//! \~
|
||||||
|
//! \code
|
||||||
|
//! PIMap<int, PIString> m;
|
||||||
|
//! m[1] = "one";
|
||||||
|
//! m[2] = "two";
|
||||||
|
//! m[4] = "four";
|
||||||
|
//! auto it = m.makeIterator();
|
||||||
|
//! while (it.next()) {
|
||||||
|
//! piCout << it.key() << it.value();
|
||||||
|
//! }
|
||||||
|
//! // 1 one
|
||||||
|
//! // 2 two
|
||||||
|
//! // 4 four
|
||||||
|
//! \endcode
|
||||||
template <typename Key, typename T>
|
template <typename Key, typename T>
|
||||||
class PIMapIterator {
|
class PIMapIteratorConst {
|
||||||
typedef PIMap<Key, T> MapType;
|
typedef PIMap<Key, T> MapType;
|
||||||
public:
|
public:
|
||||||
PIMapIterator(const PIMap<Key, T> & map, bool reverse = false): m(map), pos(-1), rev(reverse) {
|
PIMapIteratorConst(const PIMap<Key, T> & map): m(map), pos(-1) {}
|
||||||
if (rev) pos = m.size_s();
|
|
||||||
|
//! \~english Returns current key.
|
||||||
|
//! \~russian Возвращает ключ текущего элемента.
|
||||||
|
//! \~\sa \a value()
|
||||||
|
const Key & key() const {
|
||||||
|
return m._key(pos);
|
||||||
}
|
}
|
||||||
const Key & key() const {return const_cast<MapType & >(m)._key(pos);}
|
|
||||||
const T & value() const {return const_cast<MapType & >(m)._value(pos);}
|
//! \~english Returns current value.
|
||||||
T & valueRef() const {return const_cast<MapType & >(m)._value(pos);}
|
//! \~russian Возвращает значение текущего элемента.
|
||||||
|
//! \~\sa \a key()
|
||||||
|
const T & value() const {
|
||||||
|
return m._value(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Returns true if iterator can jump to next entry
|
||||||
|
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||||
|
//! \~\sa \a next()
|
||||||
inline bool hasNext() const {
|
inline bool hasNext() const {
|
||||||
if (rev) {
|
return pos < (m.size_s() - 1);
|
||||||
return pos > 0;
|
|
||||||
} else {
|
|
||||||
return pos < (m.size_s() - 1);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \~english Jump to next entry and return true if new position is valid.
|
||||||
|
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||||
|
//! \~\sa \a hasNext(), \a reset()
|
||||||
inline bool next() {
|
inline bool next() {
|
||||||
if (rev) {
|
++pos;
|
||||||
--pos;
|
return pos < m.size_s();
|
||||||
return pos >= 0;
|
|
||||||
} else {
|
|
||||||
++pos;
|
|
||||||
return pos < m.size_s();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \~english Reset iterator to initial position.
|
||||||
|
//! \~russian Переходит на начало.
|
||||||
|
//! \~\sa \a next()
|
||||||
inline void reset() {
|
inline void reset() {
|
||||||
if (rev) {
|
pos = -1;
|
||||||
pos = m.size_s();
|
|
||||||
} else {
|
|
||||||
pos = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
const MapType & m;
|
const MapType & m;
|
||||||
ssize_t pos;
|
ssize_t pos;
|
||||||
bool rev;
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \addtogroup Containers
|
||||||
|
//! \{
|
||||||
|
//! \class PIMapIteratorConstReverse
|
||||||
|
//! \brief
|
||||||
|
//! \~english Java-style reverse iterator for \a PIMap.
|
||||||
|
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
|
||||||
|
//! \~\}
|
||||||
|
//! \details
|
||||||
|
//! \~english
|
||||||
|
//! This class used to easy serial reverse access keys and values in PIMap with read only permitions.
|
||||||
|
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
|
||||||
|
//! \~russian
|
||||||
|
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке только для чтения.
|
||||||
|
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
|
||||||
|
//! \~
|
||||||
|
//! \code
|
||||||
|
//! PIMap<int, PIString> m;
|
||||||
|
//! m[1] = "one";
|
||||||
|
//! m[2] = "two";
|
||||||
|
//! m[4] = "four";
|
||||||
|
//! auto it = m.makeReverseIterator();
|
||||||
|
//! while (it.next()) {
|
||||||
|
//! piCout << it.key() << it.value();
|
||||||
|
//! }
|
||||||
|
//! // 4 four
|
||||||
|
//! // 2 two
|
||||||
|
//! // 1 one
|
||||||
|
//! \endcode
|
||||||
|
template <typename Key, typename T>
|
||||||
|
class PIMapIteratorConstReverse {
|
||||||
|
typedef PIMap<Key, T> MapType;
|
||||||
|
public:
|
||||||
|
PIMapIteratorConstReverse(const PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
|
||||||
|
|
||||||
|
//! \~english Returns current key.
|
||||||
|
//! \~russian Возвращает ключ текущего элемента.
|
||||||
|
//! \~\sa \a value()
|
||||||
|
const Key & key() const {
|
||||||
|
return m._key(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns current value.
|
||||||
|
//! \~russian Возвращает значение текущего элемента.
|
||||||
|
//! \~\sa \a key()
|
||||||
|
const T & value() const {
|
||||||
|
return m._value(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns true if iterator can jump to next entry
|
||||||
|
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||||
|
//! \~\sa \a next()
|
||||||
|
inline bool hasNext() const {
|
||||||
|
return pos > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Jump to next entry and return true if new position is valid.
|
||||||
|
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||||
|
//! \~\sa \a hasNext(), \a reset()
|
||||||
|
inline bool next() {
|
||||||
|
--pos;
|
||||||
|
return pos >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Reset iterator to initial position.
|
||||||
|
//! \~russian Переходит на начало.
|
||||||
|
//! \~\sa \a next()
|
||||||
|
inline void reset() {
|
||||||
|
pos = m.size_s();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
const MapType & m;
|
||||||
|
ssize_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \addtogroup Containers
|
||||||
|
//! \{
|
||||||
|
//! \class PIMapIterator
|
||||||
|
//! \brief
|
||||||
|
//! \~english Java-style iterator for \a PIMap.
|
||||||
|
//! \~russian Итератор Java стиля для \a PIMap.
|
||||||
|
//! \~\}
|
||||||
|
//! \details
|
||||||
|
//! \~english
|
||||||
|
//! This class used to easy serial access keys and values in PIMap with write permitions.
|
||||||
|
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
|
||||||
|
//! \~russian
|
||||||
|
//! Этот класс используется для удобного перебора ключей и значений всего словаря с доступом на запись.
|
||||||
|
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
|
||||||
|
//! \~
|
||||||
|
//! \code
|
||||||
|
//! PIMap<int, PIString> m;
|
||||||
|
//! m[1] = "one";
|
||||||
|
//! m[2] = "two";
|
||||||
|
//! m[4] = "four";
|
||||||
|
//! auto it = m.makeIterator();
|
||||||
|
//! while (it.next()) {
|
||||||
|
//! it.value().append("_!");
|
||||||
|
//! piCout << it.key() << it.value();
|
||||||
|
//! }
|
||||||
|
//! // 1 one_!
|
||||||
|
//! // 2 two_!
|
||||||
|
//! // 4 four_!
|
||||||
|
//! \endcode
|
||||||
|
template <typename Key, typename T>
|
||||||
|
class PIMapIterator {
|
||||||
|
typedef PIMap<Key, T> MapType;
|
||||||
|
public:
|
||||||
|
PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {}
|
||||||
|
|
||||||
|
//! \~english Returns current key.
|
||||||
|
//! \~russian Возвращает ключ текущего элемента.
|
||||||
|
//! \~\sa \a value()
|
||||||
|
const Key & key() const {
|
||||||
|
return m._key(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns current value.
|
||||||
|
//! \~russian Возвращает значение текущего элемента.
|
||||||
|
//! \~\sa \a key()
|
||||||
|
T & value() {
|
||||||
|
return m._value(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns true if iterator can jump to next entry
|
||||||
|
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||||
|
//! \~\sa \a next()
|
||||||
|
inline bool hasNext() const {
|
||||||
|
return pos < (m.size_s() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Jump to next entry and return true if new position is valid.
|
||||||
|
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||||
|
//! \~\sa \a hasNext(), \a reset()
|
||||||
|
inline bool next() {
|
||||||
|
++pos;
|
||||||
|
return pos < m.size_s();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Reset iterator to initial position.
|
||||||
|
//! \~russian Переходит на начало.
|
||||||
|
//! \~\sa \a next()
|
||||||
|
inline void reset() {
|
||||||
|
pos = -1;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
MapType & m;
|
||||||
|
ssize_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! \addtogroup Containers
|
||||||
|
//! \{
|
||||||
|
//! \class PIMapIteratorReverse
|
||||||
|
//! \brief
|
||||||
|
//! \~english Java-style reverse iterator for \a PIMap.
|
||||||
|
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
|
||||||
|
//! \~\}
|
||||||
|
//! \details
|
||||||
|
//! \~english
|
||||||
|
//! This class used to easy serial reverse access keys and values in PIMap with write permitions.
|
||||||
|
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
|
||||||
|
//! \~russian
|
||||||
|
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке с доступом на запись.
|
||||||
|
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
|
||||||
|
//! \~
|
||||||
|
//! \code
|
||||||
|
//! PIMap<int, PIString> m;
|
||||||
|
//! m[1] = "one";
|
||||||
|
//! m[2] = "two";
|
||||||
|
//! m[4] = "four";
|
||||||
|
//! auto it = m.makeReverseIterator();
|
||||||
|
//! while (it.next()) {
|
||||||
|
//! it.value().append("_!");
|
||||||
|
//! piCout << it.key() << it.value();
|
||||||
|
//! }
|
||||||
|
//! // 4 four_!
|
||||||
|
//! // 2 two_!
|
||||||
|
//! // 1 one_!
|
||||||
|
//! \endcode
|
||||||
|
template <typename Key, typename T>
|
||||||
|
class PIMapIteratorReverse {
|
||||||
|
typedef PIMap<Key, T> MapType;
|
||||||
|
public:
|
||||||
|
PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
|
||||||
|
|
||||||
|
//! \~english Returns current key.
|
||||||
|
//! \~russian Возвращает ключ текущего элемента.
|
||||||
|
//! \~\sa \a value()
|
||||||
|
const Key & key() const {
|
||||||
|
return m._key(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns current value.
|
||||||
|
//! \~russian Возвращает значение текущего элемента.
|
||||||
|
//! \~\sa \a key()
|
||||||
|
T & value() {
|
||||||
|
return m._value(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns true if iterator can jump to next entry
|
||||||
|
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
|
||||||
|
//! \~\sa \a next()
|
||||||
|
inline bool hasNext() const {
|
||||||
|
return pos > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Jump to next entry and return true if new position is valid.
|
||||||
|
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
|
||||||
|
//! \~\sa \a hasNext(), \a reset()
|
||||||
|
inline bool next() {
|
||||||
|
--pos;
|
||||||
|
return pos >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Reset iterator to initial position.
|
||||||
|
//! \~russian Переходит на начало.
|
||||||
|
//! \~\sa \a next()
|
||||||
|
inline void reset() {
|
||||||
|
pos = m.size_s();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
MapType & m;
|
||||||
|
ssize_t pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef PIP_STD_IOSTREAM
|
#ifdef PIP_STD_IOSTREAM
|
||||||
|
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
|
||||||
|
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
|
||||||
template<typename Key, typename Type>
|
template<typename Key, typename Type>
|
||||||
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
|
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
|
||||||
s << "{";
|
s << "{";
|
||||||
@@ -383,31 +831,36 @@ inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v)
|
|||||||
if (!first)
|
if (!first)
|
||||||
s << ", ";
|
s << ", ";
|
||||||
first = false;
|
first = false;
|
||||||
s << i->first << ": " << i->second;
|
s << i.key() << ": " << i.value();
|
||||||
}
|
}
|
||||||
s << "}";
|
s << "}";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//! \relatesalso PICout
|
||||||
|
//! \~english Output operator to \a PICout
|
||||||
|
//! \~russian Оператор вывода в \a PICout
|
||||||
template<typename Key, typename Type>
|
template<typename Key, typename Type>
|
||||||
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
|
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
|
||||||
s.space();
|
s.space();
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
s << "{";
|
s << "{";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||||
if (!first)
|
if (!first)
|
||||||
s << ", ";
|
s << ", ";
|
||||||
first = false;
|
first = false;
|
||||||
s << i->first << ": " << i->second;
|
s << i.key() << ": " << i.value();
|
||||||
}
|
}
|
||||||
s << "}";
|
s << "}";
|
||||||
s.restoreControl();
|
s.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename Type> inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
|
template<typename Key, typename Type>
|
||||||
|
inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
|
||||||
|
|
||||||
|
|
||||||
#endif // PIMAP_H
|
#endif // PIMAP_H
|
||||||
|
|||||||
@@ -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,113 @@
|
|||||||
#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.saveAndSetControls(0);
|
||||||
|
s << "(" << v.first << ", " << v.second << ")";
|
||||||
|
s.restoreControls();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Creates \a PIPair object, deducing the target type from the types of arguments.
|
||||||
|
//! \~russian Создает \a PIPair выводя типы из аргументов.
|
||||||
|
//! \~\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
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*! @file pideque.h
|
/*! \file piqueue.h
|
||||||
* @brief Queue container
|
* \brief Queue container
|
||||||
*
|
*
|
||||||
* This file declare PIQueue
|
* This file declare PIQueue
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -87,14 +87,14 @@ public:
|
|||||||
//! Unite set with "v"
|
//! Unite set with "v"
|
||||||
PISet<T> & unite(const PISet<T> & v) {
|
PISet<T> & unite(const PISet<T> & v) {
|
||||||
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
||||||
_CSet::insert(i->first, 0);
|
_CSet::insert(i.key(), 0);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Subtract set with "v"
|
//! Subtract set with "v"
|
||||||
PISet<T> & subtract(const PISet<T> & v) {
|
PISet<T> & subtract(const PISet<T> & v) {
|
||||||
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
|
||||||
_CSet::remove(i->first);
|
_CSet::remove(i.key());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,41 +121,41 @@ public:
|
|||||||
PISet<T> & operator &=(const PISet<T> & v) {return intersect(v);}
|
PISet<T> & operator &=(const PISet<T> & v) {return intersect(v);}
|
||||||
|
|
||||||
//! Returns content of set as PIVector
|
//! Returns content of set as PIVector
|
||||||
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
|
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << i.key(); return ret;}
|
||||||
|
|
||||||
//! Returns content of set as PIDeque
|
//! Returns content of set as PIDeque
|
||||||
PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
|
PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << i.key(); return ret;}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//! \relatesalso PISet @brief Returns unite of two sets
|
//! \relatesalso PISet \brief Returns unite of two sets
|
||||||
template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
|
template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
|
||||||
|
|
||||||
//! \relatesalso PISet @brief Returns subtraction of two sets
|
//! \relatesalso PISet \brief Returns subtraction of two sets
|
||||||
template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;}
|
template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;}
|
||||||
|
|
||||||
//! \relatesalso PISet @brief Returns unite of two sets
|
//! \relatesalso PISet \brief Returns unite of two sets
|
||||||
template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
|
template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
|
||||||
|
|
||||||
//! \relatesalso PISet @brief Returns intersetion of two sets
|
//! \relatesalso PISet \brief Returns intersetion of two sets
|
||||||
template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;}
|
template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;}
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
inline PICout operator <<(PICout s, const PISet<Type> & v) {
|
inline PICout operator <<(PICout s, const PISet<Type> & v) {
|
||||||
s.space();
|
s.space();
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
s << "{";
|
s << "{";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) {
|
||||||
if (!first)
|
if (!first)
|
||||||
s << ", ";
|
s << ", ";
|
||||||
first = false;
|
first = false;
|
||||||
s << i->first;
|
s << i.key();
|
||||||
}
|
}
|
||||||
s << "}";
|
s << "}";
|
||||||
s.restoreControl();
|
s.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*! @file pistack.h
|
/*! \file pistack.h
|
||||||
* @brief Stack container
|
* \brief Stack container
|
||||||
*
|
*
|
||||||
* This file declare PIStack
|
* This file declare PIStack
|
||||||
*/
|
*/
|
||||||
@@ -37,13 +37,7 @@ public:
|
|||||||
T pop() {return PIVector<T>::take_back();}
|
T pop() {return PIVector<T>::take_back();}
|
||||||
T & top() {return PIVector<T>::back();}
|
T & top() {return PIVector<T>::back();}
|
||||||
const T & top() const {return PIVector<T>::back();}
|
const T & top() const {return PIVector<T>::back();}
|
||||||
PIVector<T> toVector() {
|
PIVector<T> toVector() {return PIVector<T>(*this);}
|
||||||
PIVector<T> v;
|
|
||||||
v.reserve(PIVector<T>::size());
|
|
||||||
for (uint i = 0; i < PIVector<T>::size(); ++i)
|
|
||||||
v.push_back(PIVector<T>::at(i));
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PISTACK_H
|
#endif // PISTACK_H
|
||||||
|
|||||||
@@ -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"
|
|
||||||
|
|
||||||
* */
|
|
||||||
@@ -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 
|
||||||
|
//!
|
||||||
|
//! \~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 
|
||||||
|
//!
|
||||||
|
//! \~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 
|
||||||
|
//!
|
||||||
|
//! \~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 
|
||||||
|
//!
|
||||||
|
//! \~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(ssize_t add_size, const T & e = T()) {
|
||||||
|
ssize_t 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,28 +2295,41 @@ 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) {
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline PICout operator <<(PICout s, const PIVector<T> & v) {
|
|
||||||
s.space();
|
|
||||||
s.setControl(0, true);
|
|
||||||
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();
|
return s;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! \relatesalso PICout
|
||||||
|
//! \~english Output operator to \a PICout
|
||||||
|
//! \~russian Оператор вывода в \a PICout
|
||||||
|
template<typename T>
|
||||||
|
inline PICout operator <<(PICout s, const PIVector<T> & v) {
|
||||||
|
s.space();
|
||||||
|
s.saveAndSetControls(0);
|
||||||
|
s << "{";
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) {
|
||||||
|
s << v[i];
|
||||||
|
if (i < v.size() - 1) {
|
||||||
|
s << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s << "}";
|
||||||
|
s.restoreControls();
|
||||||
return s;
|
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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +292,7 @@ protected:
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
|
inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
s << "{";
|
s << "{";
|
||||||
for (size_t i = 0; i < v.rows(); ++i) {
|
for (size_t i = 0; i < v.rows(); ++i) {
|
||||||
s << "{ ";
|
s << "{ ";
|
||||||
@@ -310,7 +305,7 @@ inline PICout operator <<(PICout s, const PIVector2D<T> & v) {
|
|||||||
}
|
}
|
||||||
if (v.isEmpty()) s << "{ }";
|
if (v.isEmpty()) s << "{ }";
|
||||||
s << "}";
|
s << "}";
|
||||||
s.restoreControl();
|
s.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,15 +257,23 @@
|
|||||||
# 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
|
||||||
|
# undef DEPRECATEDM
|
||||||
# define DEPRECATED __attribute__((deprecated))
|
# define DEPRECATED __attribute__((deprecated))
|
||||||
|
# define DEPRECATEDM(msg) __attribute__((deprecated(msg)))
|
||||||
# if CC_GCC_VERSION > 0x025F // > 2.95
|
# if CC_GCC_VERSION > 0x025F // > 2.95
|
||||||
|
# pragma GCC diagnostic warning "-Wdeprecated-declarations"
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
# define HAS_LOCALE
|
# define HAS_LOCALE
|
||||||
# endif
|
# endif
|
||||||
# ifdef MAC_OS
|
# ifdef MAC_OS
|
||||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
|
# pragma GCC diagnostic ignored "-Wundefined-bool-conversion"
|
||||||
# pragma GCC diagnostic ignored "-Wc++11-extensions"
|
# pragma GCC diagnostic ignored "-Wc++11-extensions"
|
||||||
# endif
|
# endif
|
||||||
@@ -193,7 +289,9 @@
|
|||||||
|
|
||||||
#ifdef CC_VC
|
#ifdef CC_VC
|
||||||
# undef DEPRECATED
|
# undef DEPRECATED
|
||||||
# define DEPRECATED
|
# undef DEPRECATEDM
|
||||||
|
# define DEPRECATED __declspec(deprecated)
|
||||||
|
# define DEPRECATEDM(msg) __declspec(deprecated(msg))
|
||||||
# pragma warning(disable: 4018)
|
# pragma warning(disable: 4018)
|
||||||
# pragma warning(disable: 4061)
|
# pragma warning(disable: 4061)
|
||||||
# pragma warning(disable: 4100)
|
# pragma warning(disable: 4100)
|
||||||
@@ -218,10 +316,12 @@
|
|||||||
|
|
||||||
#ifdef CC_OTHER
|
#ifdef CC_OTHER
|
||||||
# undef DEPRECATED
|
# undef DEPRECATED
|
||||||
|
# undef DEPRECATEDM
|
||||||
# define DEPRECATED
|
# define DEPRECATED
|
||||||
|
# define DEPRECATEDM(msg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif //DOXYGEN
|
||||||
// Private data macros
|
// Private data macros
|
||||||
#ifndef DOXYGEN
|
#ifndef DOXYGEN
|
||||||
|
|
||||||
@@ -274,28 +374,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 +425,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 +473,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 +486,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 +860,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>
|
||||||
|
|||||||
525
libs/main/core/pibinarystream.h
Normal file
525
libs/main/core/pibinarystream.h
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
/*! \file pibinarystream.h
|
||||||
|
* \ingroup Core
|
||||||
|
* \~\brief
|
||||||
|
* \~english Binary serialization interface
|
||||||
|
* \~russian Интерфейс бинарной сериализации
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
PIP - Platform Independent Primitives
|
||||||
|
Binary serialization interface
|
||||||
|
Ivan Pelipenko peri4ko@yandex.ru
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PIBINARYSTREAM_H
|
||||||
|
#define PIBINARYSTREAM_H
|
||||||
|
|
||||||
|
#include "pimemoryblock.h"
|
||||||
|
#include "pibitarray.h"
|
||||||
|
#include "pimap.h"
|
||||||
|
#include "pivector2d.h"
|
||||||
|
|
||||||
|
#define PIP_BINARY_STREAM
|
||||||
|
|
||||||
|
#define BINARY_STREAM_FRIEND(T) \
|
||||||
|
template<typename P> friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v); \
|
||||||
|
template<typename P> friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v);
|
||||||
|
#define BINARY_STREAM_WRITE(T) \
|
||||||
|
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v)
|
||||||
|
#define BINARY_STREAM_READ(T) \
|
||||||
|
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v)
|
||||||
|
|
||||||
|
|
||||||
|
//! \ingroup Core
|
||||||
|
//! \~\brief
|
||||||
|
//! \~english Binary serialization interface.
|
||||||
|
//! \~russian Интерфейс бинарной сериализации.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english In your class you should implement this methods:
|
||||||
|
//! \~russian В производном классе вы должны реализовать следующие методы:
|
||||||
|
//! \~\code
|
||||||
|
//! bool binaryStreamAppendImp (const void * d, size_t s);
|
||||||
|
//! bool binaryStreamTakeImp (void * d, size_t s);
|
||||||
|
//! ssize_t binaryStreamSizeImp () const;
|
||||||
|
//! \endcode
|
||||||
|
//! \~english Function binaryStreamSizeImp should return -1 if size unknown.
|
||||||
|
//! \~russian Функция binaryStreamSizeImp должна возвращать -1 если нет информации о размере.
|
||||||
|
//! \~english See details \ref iostream.
|
||||||
|
//! \~russian Подробнее \ref iostream.
|
||||||
|
template<typename P>
|
||||||
|
class PIBinaryStream {
|
||||||
|
public:
|
||||||
|
//! \~russian Записать данные
|
||||||
|
bool binaryStreamAppend(const void * d, size_t s) {
|
||||||
|
if (!static_cast<P*>(this)->binaryStreamAppendImp(d, s)) {
|
||||||
|
return false;
|
||||||
|
printf("[PIBinaryStream] binaryStreamAppend() error\n");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//! \~russian Прочитать данные
|
||||||
|
bool binaryStreamTake(void * d, size_t s) {
|
||||||
|
if (!static_cast<P*>(this)->binaryStreamTakeImp(d, s)) {
|
||||||
|
return false;
|
||||||
|
printf("[PIBinaryStream] binaryStreamTake() error\n");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~russian Узнать оставшийся размер
|
||||||
|
//!\~\details
|
||||||
|
//!\~russian Возвращает -1 если нет информации о размере
|
||||||
|
ssize_t binaryStreamSize() const {
|
||||||
|
return static_cast<P*>(this)->binaryStreamSizeImp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~russian Записать данные
|
||||||
|
template<typename T>
|
||||||
|
void binaryStreamAppend(T v) {binaryStreamAppend(&v, sizeof(v));}
|
||||||
|
|
||||||
|
//! \~russian Прочитать int
|
||||||
|
int binaryStreamTakeInt() {
|
||||||
|
int r = 0;
|
||||||
|
binaryStreamTake(&r, sizeof(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// helper class to detect default operators
|
||||||
|
template<typename P>
|
||||||
|
class PIBinaryStreamTrivialRef {
|
||||||
|
public:
|
||||||
|
PIBinaryStreamTrivialRef(PIBinaryStream<P> & s): p(s) {}
|
||||||
|
PIBinaryStream<P> & p;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename P, typename T> inline PIBinaryStream<P> & operator <<(PIBinaryStreamTrivialRef<P> s, const T & v) {
|
||||||
|
s.p << v;
|
||||||
|
return s.p;
|
||||||
|
}
|
||||||
|
template<typename P, typename T> inline PIBinaryStream<P> & operator >>(PIBinaryStreamTrivialRef<P> s, T & v) {
|
||||||
|
s.p >> v;
|
||||||
|
return s.p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// specify types
|
||||||
|
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const bool v) {
|
||||||
|
s.binaryStreamAppend((uchar)v);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, bool & v) {
|
||||||
|
uchar c;
|
||||||
|
s.binaryStreamTake(&c, sizeof(c));
|
||||||
|
v = c;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename P> inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMemoryBlock v) {
|
||||||
|
s.binaryStreamAppend(v.data(), v.size());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P> inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMemoryBlock v) {
|
||||||
|
s.binaryStreamTake(v.data(), v.size());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// store simple types
|
||||||
|
|
||||||
|
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & v) {
|
||||||
|
//piCout << "<< enum";
|
||||||
|
s.binaryStreamAppend((int)v);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStreamTrivialRef<P> operator <<(PIBinaryStream<P> & s, const T & v) {
|
||||||
|
s.binaryStreamAppend(&v, sizeof(v));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator for PIVector of any trivial copyable type
|
||||||
|
//! \~russian Оператор сохранения для PIVector тривиальных типов
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
|
||||||
|
//piCout << "<< vector trivial default";
|
||||||
|
s.binaryStreamAppend((int)v.size());
|
||||||
|
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
|
||||||
|
//piCout << "<< vector trivial custom";
|
||||||
|
s.binaryStreamAppend((int)v.size());
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator for PIDeque of any trivial copyable type
|
||||||
|
//! \~russian Оператор сохранения для PIDeque тривиальных типов
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
|
||||||
|
//piCout << "<< deque trivial default";
|
||||||
|
s.binaryStreamAppend((int)v.size());
|
||||||
|
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
|
||||||
|
//piCout << "<< deque trivial custom";
|
||||||
|
s.binaryStreamAppend((int)v.size());
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator for PIVector2D of any trivial copyable type
|
||||||
|
//! \~russian Оператор сохранения для PIVector2D тривиальных типов
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
|
||||||
|
//piCout << "<< vector2d trivial default";
|
||||||
|
s.binaryStreamAppend((int)v.rows());
|
||||||
|
s.binaryStreamAppend((int)v.cols());
|
||||||
|
s.binaryStreamAppend(v.data(), v.size() * sizeof(T));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() << std::declval<const T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
|
||||||
|
//piCout << "<< vector2d trivial custom";
|
||||||
|
s.binaryStreamAppend((int)v.rows());
|
||||||
|
s.binaryStreamAppend((int)v.cols());
|
||||||
|
s << v.toPlainVector();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator
|
||||||
|
//! \~russian Оператор сохранения
|
||||||
|
template<typename P>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator
|
||||||
|
//! \~russian Оператор сохранения
|
||||||
|
template<typename P, typename Type0, typename Type1>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// restore simple types
|
||||||
|
|
||||||
|
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & v) {
|
||||||
|
//piCout << ">> enum";
|
||||||
|
v = (T)s.binaryStreamTakeInt();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if<!std::is_enum<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStreamTrivialRef<P> operator >>(PIBinaryStream<P> & s, T & v) {
|
||||||
|
if (!s.binaryStreamTake(&v, sizeof(v))) {
|
||||||
|
printf("error with %s\n", __PIP_TYPENAME__(T));
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator for PIVector of any trivial copyable type
|
||||||
|
//! \~russian Оператор извлечения для PIVector тривиальных типов
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||||
|
//piCout << ">> vector trivial default";
|
||||||
|
int sz = s.binaryStreamTakeInt();
|
||||||
|
v._resizeRaw(sz);
|
||||||
|
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||||
|
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||||
|
//piCout << ">> vector trivial custom";
|
||||||
|
int sz = s.binaryStreamTakeInt();
|
||||||
|
v._resizeRaw(sz);
|
||||||
|
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator for PIDeque of any trivial copyable type
|
||||||
|
//! \~russian Оператор извлечения для PIDeque тривиальных типов
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||||
|
//piCout << ">> deque trivial default";
|
||||||
|
int sz = s.binaryStreamTakeInt();
|
||||||
|
v._resizeRaw(sz);
|
||||||
|
if (!s.binaryStreamTake(v.data(), sz * sizeof(T))) {
|
||||||
|
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||||
|
//piCout << ">> deque trivial custom";
|
||||||
|
int sz = s.binaryStreamTakeInt();
|
||||||
|
v._resizeRaw(sz);
|
||||||
|
for (int i = 0; i < sz; ++i) s >> v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator for PIVector2D of any trivial copyable type
|
||||||
|
//! \~russian Оператор извлечения для PIVector2D тривиальных типов
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if< std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||||||
|
//piCout << ">> vector2d trivial default";
|
||||||
|
int r, c;
|
||||||
|
r = s.binaryStreamTakeInt();
|
||||||
|
c = s.binaryStreamTakeInt();
|
||||||
|
v._resizeRaw(r, c);
|
||||||
|
if (!s.binaryStreamTake(v.data(), v.size() * sizeof(T))) {
|
||||||
|
printf("error with PIVector2D<%s>\n", __PIP_TYPENAME__(T));
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<typename P, typename T,
|
||||||
|
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
||||||
|
typename std::enable_if<!std::is_same<decltype(std::declval<PIBinaryStream<P>&>() >> std::declval<T &>()), PIBinaryStreamTrivialRef<P>>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||||||
|
//piCout << ">> vector2d trivial custom";
|
||||||
|
int r, c;
|
||||||
|
PIVector<T> tmp;
|
||||||
|
r = s.binaryStreamTakeInt();
|
||||||
|
c = s.binaryStreamTakeInt();
|
||||||
|
s >> tmp;
|
||||||
|
v = PIVector2D<T>(r, c, tmp);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator
|
||||||
|
//! \~russian Оператор извлечения
|
||||||
|
template<typename P>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIBitArray & v) {s >> v.size_ >> v.data_; return s;}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator
|
||||||
|
//! \~russian Оператор извлечения
|
||||||
|
template<typename P, typename Type0, typename Type1>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// store complex types
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator for PIVector of any compound type
|
||||||
|
//! \~russian Оператор сохранения для PIVector сложных типов
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector<T> & v) {
|
||||||
|
//piCout << "<< vector complex";
|
||||||
|
s.binaryStreamAppend(int(v.size_s()));
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator for PIDeque of any compound type
|
||||||
|
//! \~russian Оператор сохранения для PIDeque сложных типов
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIDeque<T> & v) {
|
||||||
|
//piCout << "<< deque complex";
|
||||||
|
s.binaryStreamAppend(int(v.size_s()));
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) s << v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator for PIVector2D of any compound type
|
||||||
|
//! \~russian Оператор сохранения для PIVector2D сложных типов
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIVector2D<T> & v) {
|
||||||
|
//piCout << "<< vector2d complex";
|
||||||
|
s.binaryStreamAppend(int(v.rows()));
|
||||||
|
s.binaryStreamAppend(int(v.cols()));
|
||||||
|
s << v.toPlainVector();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// restore complex types
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator for PIVector of any compound type
|
||||||
|
//! \~russian Оператор извлечения для PIVector сложных типов
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector<T> & v) {
|
||||||
|
//piCout << ">> vector complex";
|
||||||
|
/*if (s.size_s() < 4) {
|
||||||
|
printf("error with PIVector<%s>\n", __PIP_TYPENAME__(T));
|
||||||
|
assert(s.size_s() >= 4);
|
||||||
|
}*/
|
||||||
|
v.resize(s.binaryStreamTakeInt());
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) s >> v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator for PIDeque of any compound type
|
||||||
|
//! \~russian Оператор извлечения для PIDeque сложных типов
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIDeque<T> & v) {
|
||||||
|
//piCout << ">> deque complex";
|
||||||
|
/*if (s.size_s() < 4) {
|
||||||
|
printf("error with PIDeque<%s>\n", __PIP_TYPENAME__(T));
|
||||||
|
assert(s.size_s() >= 4);
|
||||||
|
}*/
|
||||||
|
v.resize(s.binaryStreamTakeInt());
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) s >> v[i];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator for PIVector2D of any compound type
|
||||||
|
//! \~russian Оператор извлечения для PIVector2D сложных типов
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIVector2D<T> & v) {
|
||||||
|
//piCout << ">> vector2d complex";
|
||||||
|
/*if (s.size_s() < 8) {
|
||||||
|
printf("error with PIVecto2Dr<%s>\n", __PIP_TYPENAME__(T));
|
||||||
|
assert(s.size_s() >= 8);
|
||||||
|
}*/
|
||||||
|
int r, c;
|
||||||
|
PIVector<T> tmp;
|
||||||
|
r = s.binaryStreamTakeInt();
|
||||||
|
c = s.binaryStreamTakeInt();
|
||||||
|
s >> tmp;
|
||||||
|
v = PIVector2D<T>(r, c, tmp);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// other types
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Store operator
|
||||||
|
//! \~russian Оператор сохранения
|
||||||
|
template <typename P, typename Key, typename T>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIMap<Key, T> & v) {
|
||||||
|
s.binaryStreamAppend((int)v.pim_index.size_s());
|
||||||
|
for (uint i = 0; i < v.size(); ++i) {
|
||||||
|
s.binaryStreamAppend((int)v.pim_index[i].index);
|
||||||
|
s << v.pim_index[i].key;
|
||||||
|
}
|
||||||
|
s << v.pim_content;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Restore operator
|
||||||
|
//! \~russian Оператор извлечения
|
||||||
|
template <typename P, typename Key, typename T>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIMap<Key, T> & v) {
|
||||||
|
/*if (s.size_s() < 4) {
|
||||||
|
printf("error with PIMap<%s, %s>\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
|
||||||
|
assert(s.size_s() >= 4);
|
||||||
|
}*/
|
||||||
|
int sz = s.binaryStreamTakeInt(); v.pim_index.resize(sz);
|
||||||
|
int ind = 0;
|
||||||
|
for (int i = 0; i < sz; ++i) {
|
||||||
|
ind = s.binaryStreamTakeInt();
|
||||||
|
s >> v.pim_index[i].key;
|
||||||
|
v.pim_index[i].index = ind;
|
||||||
|
}
|
||||||
|
s >> v.pim_content;
|
||||||
|
if (v.pim_content.size_s() != v.pim_index.size_s()) {
|
||||||
|
piCout << "Warning: loaded invalid PIMap, clear";
|
||||||
|
v.clear();
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// non-defined complex types
|
||||||
|
|
||||||
|
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const T & ) {
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator << for complex type!");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename P, typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
||||||
|
inline PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, T & ) {
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value, "[PIBinaryStream] Error: using undeclared operator >> for complex type!");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
|
|
||||||
PICout operator <<(PICout s, const PIBitArray & ba) {
|
PICout operator <<(PICout s, const PIBitArray & ba) {
|
||||||
s.space();
|
s.space();
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
for (uint i = 0; i < ba.bitSize(); ++i) {
|
for (uint i = 0; i < ba.bitSize(); ++i) {
|
||||||
s << int(ba[i]);
|
s << int(ba[i]);
|
||||||
if (i % 8 == 7) s << ' ';
|
if (i % 8 == 7) s << ' ';
|
||||||
}
|
}
|
||||||
s.restoreControl();
|
s.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -26,8 +28,10 @@
|
|||||||
#include "pivector.h"
|
#include "pivector.h"
|
||||||
|
|
||||||
class PIP_EXPORT PIBitArray {
|
class PIP_EXPORT PIBitArray {
|
||||||
friend PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v);
|
template <typename P>
|
||||||
friend PIByteArray & operator >>(PIByteArray & s, PIBitArray & v);
|
friend PIBinaryStream<P> & operator >>(PIBinaryStream<P> & s, PIBitArray & v);
|
||||||
|
template <typename P>
|
||||||
|
friend PIBinaryStream<P> & operator <<(PIBinaryStream<P> & s, const PIBitArray & v);
|
||||||
public:
|
public:
|
||||||
PIBitArray(const int & size = 0) {resize(size);}
|
PIBitArray(const int & size = 0) {resize(size);}
|
||||||
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
|
PIBitArray(uchar val) {resize(sizeof(val) * 8); data_[0] = val;}
|
||||||
|
|||||||
@@ -20,6 +20,55 @@
|
|||||||
#include "pibytearray.h"
|
#include "pibytearray.h"
|
||||||
#include "pistringlist.h"
|
#include "pistringlist.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "picrc.h"
|
||||||
|
|
||||||
|
//! \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.
|
||||||
|
//! See details \ref iostream.
|
||||||
|
//! This class use PIDeque<uchar> and provide some handle function
|
||||||
|
//! to manipulate it.
|
||||||
|
//! \~russian
|
||||||
|
//! %PIByteArray используется для хранения байтов.
|
||||||
|
//! Он может быть сконструирован из любых даных.
|
||||||
|
//! Можно использовать %PIByteArray как потоковый объект
|
||||||
|
//! для сериализации/десериализации любых типов и данных.
|
||||||
|
//! Подробнее \ref iostream.
|
||||||
|
//! Этот класс использует PIDeque<uchar> и предоставляет набор
|
||||||
|
//! удобных методов для работы с байтами.
|
||||||
|
//!
|
||||||
|
//! \~english \section PIByteArray_sec0 Usage
|
||||||
|
//! \~russian \section PIByteArray_sec0 Использование
|
||||||
|
//! \~english
|
||||||
|
//! %PIByteArray subclass PIBinaryStream and can be used to store custom data and manipulate it.
|
||||||
|
//! 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 наследован от PIBinaryStream и может быть использован для сохранения любых данных и работы с ними.
|
||||||
|
//! Операторы сохранения добавляют данные в конец массива, а операторы извлечения
|
||||||
|
//! берут данные из его начала.
|
||||||
|
//! Также есть методы для преобразования в Hex и Base64.
|
||||||
|
//!
|
||||||
|
//! \~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] = {
|
||||||
@@ -221,22 +270,61 @@ 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 {
|
uchar PIByteArray::checksumCRC8() const {
|
||||||
|
return standardCRC_8().calculate(data(), size());
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort PIByteArray::checksumCRC16() const {
|
||||||
|
return standardCRC_16().calculate(data(), size());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint PIByteArray::checksumCRC32() const {
|
||||||
|
return standardCRC_32().calculate(data(), size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \~\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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,14 +406,14 @@ PIByteArray PIByteArray::fromHex(PIString str) {
|
|||||||
|
|
||||||
PICout operator <<(PICout s, const PIByteArray & ba) {
|
PICout operator <<(PICout s, const PIByteArray & ba) {
|
||||||
s.space();
|
s.space();
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
s << "{";
|
s << "{";
|
||||||
for (uint i = 0; i < ba.size(); ++i) {
|
for (uint i = 0; i < ba.size(); ++i) {
|
||||||
s << ba[i];
|
s << ba[i];
|
||||||
if (i < ba.size() - 1) s << ", ";
|
if (i < ba.size() - 1) s << ", ";
|
||||||
}
|
}
|
||||||
s << "}";
|
s << "}";
|
||||||
s.restoreControl();
|
s.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,38 +429,3 @@ std::ostream &operator <<(std::ostream & s, const PIByteArray & ba) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
s.clear();
|
|
||||||
v.clear();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
int sz = 0;
|
|
||||||
s >> sz;
|
|
||||||
if (sz > s.size_s()) {
|
|
||||||
piCout << "[PIByteArray] Warning: operator >> wants too much data, discard!" << sz << s.size_s();
|
|
||||||
s.clear();
|
|
||||||
v.clear();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
v.resize(sz);
|
|
||||||
if (sz > 0) {
|
|
||||||
memcpy(v.data(), s.data(), sz);
|
|
||||||
s.remove(0, sz);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {
|
|
||||||
s << int(v.size_s());
|
|
||||||
int os = s.size_s();
|
|
||||||
if (v.size_s() > 0) {
|
|
||||||
s.enlarge(v.size_s());
|
|
||||||
memcpy(s.data(os), v.data(), v.size());
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -24,105 +27,1036 @@
|
|||||||
#define PIBYTEARRAY_H
|
#define PIBYTEARRAY_H
|
||||||
|
|
||||||
#include "pichar.h"
|
#include "pichar.h"
|
||||||
#include "pibitarray.h"
|
#include "pibinarystream.h"
|
||||||
#include "pimap.h"
|
#include <stdio.h>
|
||||||
#include "pivector2d.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
|
class PIP_EXPORT PIByteArray: public PIBinaryStream<PIByteArray>
|
||||||
* to serialize/deserialize any objects and data.
|
|
||||||
* This class based on PIDeque<uchar> and provide some handle function
|
|
||||||
* to manipulate it.
|
|
||||||
*
|
|
||||||
* @section PIByteArray_sec0 Usage
|
|
||||||
* %PIByteArray can be used to store custom data and manipulate it. There are many
|
|
||||||
* stream operators to store/restore common types to byte array. Store operators
|
|
||||||
* places data at the end of array, restore operators takes data from the beginning
|
|
||||||
* of array.
|
|
||||||
* In addition there are Hex and Base64 convertions
|
|
||||||
*
|
|
||||||
* One of the major usage of %PIByteArray is stream functions. You can form binary
|
|
||||||
* packet from many types (also dynamic types, e.g. PIVector) with one line:
|
|
||||||
* @snippet pibytearray.cpp 0
|
|
||||||
*
|
|
||||||
* Or you can descibe stream operator of your own type and store/restore vectors of
|
|
||||||
* your type:
|
|
||||||
* @snippet pibytearray.cpp 1
|
|
||||||
*
|
|
||||||
* For store/restore custom data blocks there is PIByteArray::RawData class. Stream
|
|
||||||
* operators of this class simply store/restore data block to/from byte array.
|
|
||||||
* @snippet pibytearray.cpp 2
|
|
||||||
*
|
|
||||||
* @section PIByteArray_sec1 Attention
|
|
||||||
* Stream operator of %PIByteArray store byte array as vector, not simply append
|
|
||||||
* content of byte array. This operators useful to transmit custom data as %PIByteArray
|
|
||||||
* packed into parent byte array, e.g. to form packet from %PIByteArray.
|
|
||||||
* To append one byte array to another use funtion \a append().
|
|
||||||
* @snippet pibytearray.cpp 3
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class PIP_EXPORT PIByteArray: public PIDeque<uchar>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef ::PIMemoryBlock RawData DEPRECATEDM("use PIMemoryBlock instead");
|
||||||
|
|
||||||
//! Constructs an empty byte array
|
//! \~english Constructs an empty byte array
|
||||||
PIByteArray() {;}
|
//! \~russian Создает пустой байтовый массив
|
||||||
|
PIByteArray() {}
|
||||||
|
|
||||||
PIByteArray(const PIByteArray & o): PIDeque<uchar>(o) {}
|
//! \~english Constructs copy of byte array "o"
|
||||||
|
//! \~russian Создает копию байтового массива "o"
|
||||||
|
PIByteArray(const PIByteArray & o): d(o.d) {}
|
||||||
|
|
||||||
PIByteArray(PIByteArray && o): PIDeque<uchar>(std::move(o)) {}
|
//! \~english Constructs copy of byte array "o"
|
||||||
|
//! \~russian Создает копию байтового массива "o"
|
||||||
|
PIByteArray(const PIDeque<uchar> & o): d(o) {}
|
||||||
|
|
||||||
//! Constructs 0-filled byte array with size "size"
|
PIByteArray(PIByteArray && o): d(std::move(o.d)) {}
|
||||||
|
|
||||||
|
//! \~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"
|
||||||
PIByteArray(const void * data, const uint size): PIDeque<uchar>((const uchar*)data, size_t(size)) {}
|
//! \~russian Создает байтовый массив из данных по указателю "data" размером "size"
|
||||||
|
PIByteArray(const void * data, const uint size): d((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"
|
||||||
PIByteArray(const uint size, uchar t): PIDeque<uchar>(size, t) {}
|
//! \~russian Создает заполненный "t" байтовый массив размером "size"
|
||||||
|
PIByteArray(const uint size, uchar t): d(size, t) {}
|
||||||
|
|
||||||
|
//! \~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
|
||||||
|
//! PIByteArray v{1,2,3};
|
||||||
|
//! piCout << v; // {1, 2, 3}
|
||||||
|
//! \endcode
|
||||||
|
PIByteArray(std::initializer_list<uchar> init_list) : d(init_list) {}
|
||||||
|
|
||||||
|
//! \~english Swaps array `v` other with this array.
|
||||||
|
//! \~russian Меняет местами массив `v` с этим массивом.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english This operation is very fast and never fails.
|
||||||
|
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
|
||||||
|
inline void swap(PIByteArray & other) {
|
||||||
|
d.swap(other.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Iterator to the first element.
|
||||||
|
//! \~russian Итератор на первый элемент.
|
||||||
|
//! \~\details 
|
||||||
|
//!
|
||||||
|
//! \~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 PIDeque<uchar>::iterator begin() {return d.begin();}
|
||||||
|
|
||||||
|
//! \~english Iterator to the element following the last element.
|
||||||
|
//! \~russian Итератор на элемент, следующий за последним элементом.
|
||||||
|
//! \~\details 
|
||||||
|
//!
|
||||||
|
//! \~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 PIDeque<uchar>::iterator end() {return d.end();}
|
||||||
|
|
||||||
|
inline PIDeque<uchar>::const_iterator begin() const {return d.begin();}
|
||||||
|
inline PIDeque<uchar>::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.
|
||||||
|
//! 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 PIDeque<uchar>::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.
|
||||||
|
//! 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 PIDeque<uchar>::reverse_iterator rend() {return d.rend();}
|
||||||
|
|
||||||
|
inline PIDeque<uchar>::const_reverse_iterator rbegin() const {return d.rbegin();}
|
||||||
|
inline PIDeque<uchar>::const_reverse_iterator rend() const {return d.rend();}
|
||||||
|
|
||||||
|
//! \~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 d.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 d.size_s();}
|
||||||
|
|
||||||
|
//! \~english Same as \a size().
|
||||||
|
//! \~russian Синоним \a size().
|
||||||
|
//! \~\sa \a size(), \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||||
|
inline size_t length() const {return d.length();}
|
||||||
|
|
||||||
|
//! \~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 d.capacity();}
|
||||||
|
|
||||||
|
//! \~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 d.isEmpty();}
|
||||||
|
|
||||||
|
//! \~english Checks if the container has elements.
|
||||||
|
//! \~russian Проверяет не пуст ли массив.
|
||||||
|
//! \~\return
|
||||||
|
//! \~english **true** if the container is not empty, **false** otherwise
|
||||||
|
//! \~russian **true** если массив не пуст, **false** иначе.
|
||||||
|
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
|
||||||
|
inline bool isNotEmpty() const {return d.isNotEmpty();}
|
||||||
|
|
||||||
|
//! \~english Tests whether at least one element in the array
|
||||||
|
//! passes the test implemented by the provided function `test`.
|
||||||
|
//! \~russian Проверяет, удовлетворяет ли какой-либо элемент массива условию,
|
||||||
|
//! заданному в передаваемой функции `test`.
|
||||||
|
//! \~\return
|
||||||
|
//! \~english **true** if, in the array,
|
||||||
|
//! it finds an element for which the provided function returns **true**;
|
||||||
|
//! otherwise it returns **false**. Always returns **false** if is empty.
|
||||||
|
//! \~russian **true** если хотя бы для одного элемента
|
||||||
|
//! передаваемая функция возвращает **true**, в остальных случаях **false**.
|
||||||
|
//! Метод возвращает **false** при любом условии для пустого массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a every(), \a contains(), \a entries(), \a forEach()
|
||||||
|
inline bool any(std::function<bool(uchar e)> test) const {
|
||||||
|
return d.any(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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
|
||||||
|
//! \~\sa \a any(), \a contains(), \a entries(), \a forEach()
|
||||||
|
inline bool every(std::function<bool(uchar e)> test) const {
|
||||||
|
return d.every(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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`.
|
||||||
|
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
|
||||||
|
//! \~\sa \a at()
|
||||||
|
inline uchar & operator [](size_t index) {return d[index];}
|
||||||
|
inline uchar operator [](size_t index) const {return d[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 uchar at(size_t index) const {return d.at(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 uchar & back() {return d.back();}
|
||||||
|
inline uchar back() const {return d.back();}
|
||||||
|
|
||||||
|
//! \~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 uchar & front() {return d.front();}
|
||||||
|
inline uchar front() const {return d.front();}
|
||||||
|
|
||||||
|
//! \~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
|
||||||
|
//! PIByteArray 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()
|
||||||
|
inline bool contains(uchar e, ssize_t start = 0) const {
|
||||||
|
return d.contains(e, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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, что означает, что просматривается весь массив.
|
||||||
|
//! \~\sa \a every(), \a any(), \a contains(), \a indexOf()
|
||||||
|
inline int entries(uchar e, ssize_t start = 0) const {
|
||||||
|
return d.entries(e, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Count elements in the array passes the test implemented by the provided function `test`.
|
||||||
|
//! \~russian Подсчитывает количество элементов в массиве,
|
||||||
|
//! проходящих по условию, заданному в передаваемой функции `test`.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Overloaded function.
|
||||||
|
//! Optional argument `start` - the position in this array at which to begin searching.
|
||||||
|
//! If the index is greater than or equal to the array's size,
|
||||||
|
//! 0 is returned, which means the array will not be searched.
|
||||||
|
//! If the provided index value is a negative number,
|
||||||
|
//! it is taken as the offset from the end of the array.
|
||||||
|
//! Note: if the provided index is negative,
|
||||||
|
//! the array is still searched from front to back.
|
||||||
|
//! Default: 0 (entire array is searched).
|
||||||
|
//! \~russian Перегруженная функция.
|
||||||
|
//! Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||||
|
//! Если индекс больше или равен длине массива,
|
||||||
|
//! возвращается 0, что означает, что массив даже не просматривается.
|
||||||
|
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||||
|
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||||
|
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||||
|
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||||
|
//! \~\sa \a every(), \a any(), \a contains(), \a indexWhere()
|
||||||
|
inline int entries(std::function<bool(uchar e)> test, ssize_t start = 0) const {
|
||||||
|
return d.entries(test, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns the first index at which a given element `e`
|
||||||
|
//! can be found in the array, or `-1` if it is not present.
|
||||||
|
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
|
||||||
|
//! может быть найден в массиве или `-1`, если такого индекса нет.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Optional argument `start` - the position in this array at which to begin searching.
|
||||||
|
//! If the index is greater than or equal to the array's size,
|
||||||
|
//! `-1` is returned, which means the array will not be searched.
|
||||||
|
//! If the provided index value is a negative number,
|
||||||
|
//! it is taken as the offset from the end of the array.
|
||||||
|
//! Note: if the provided index is negative,
|
||||||
|
//! the array is still searched from front to back.
|
||||||
|
//! Default: 0 (entire array is searched).
|
||||||
|
//! \~russian Опциональный аргумент `start` указывает на индекс в массиве, откуда будет начинаться поиск.
|
||||||
|
//! Если индекс больше или равен длине массива,
|
||||||
|
//! возвращается `-1`, что означает, что массив даже не просматривается.
|
||||||
|
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
|
||||||
|
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
|
||||||
|
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
|
||||||
|
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
|
||||||
|
//! \~\code
|
||||||
|
//! PIByteArray 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 uchar & e, ssize_t start = 0) const {
|
||||||
|
return d.indexOf(e, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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
|
||||||
|
//! PIByteArray v{2, 5, 9};
|
||||||
|
//! piCout << v.indexWhere([](const uchar & s){return s > 3;}); // 1
|
||||||
|
//! piCout << v.indexWhere([](const uchar & s){return s > 3;}, 2); // 2
|
||||||
|
//! piCout << v.indexWhere([](const uchar & s){return s > 10;}); // -1
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a indexOf(), \a lastIndexOf(), \a lastIndexWhere(), \a contains()
|
||||||
|
inline ssize_t indexWhere(std::function<bool(const uchar & e)> test, ssize_t start = 0) const {
|
||||||
|
return d.indexWhere(test, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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
|
||||||
|
//! PIByteArray 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 uchar & e, ssize_t start = -1) const {
|
||||||
|
return d.lastIndexOf(e, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 uchar & e)> test, ssize_t start = -1) const {
|
||||||
|
return d.lastIndexWhere(test, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 которого брать указатель.
|
||||||
|
//! По умолчанию указывает на начало массива.
|
||||||
|
inline uchar * data(size_t index = 0) {return d.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 которого брать указатель.
|
||||||
|
//! По умолчанию указывает на начало массива.
|
||||||
|
inline const uchar * data(size_t index = 0) const {return d.data(index);}
|
||||||
|
|
||||||
|
//! \~english Clear array, remove all elements.
|
||||||
|
//! \~russian Очищает массив, удаляет все элементы.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\note
|
||||||
|
//! \~english Reserved memory will not be released.
|
||||||
|
//! \~russian Зарезервированная память не освободится.
|
||||||
|
//! \~\sa \a resize()
|
||||||
|
inline PIByteArray & clear() {
|
||||||
|
resize(0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Assigns element 'e' to all items in the array.
|
||||||
|
//! \~russian Заполняет весь массив копиями элемента 'e'.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a resize()
|
||||||
|
inline PIByteArray & fill(uchar e = 0) {
|
||||||
|
d.fill(e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Assigns result of function 'f(size_t i)' to all items in the array.
|
||||||
|
//! \~russian Заполняет весь массив результатом вызова функции 'f(size_t i)'.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a resize()
|
||||||
|
inline PIByteArray & fill(std::function<uchar(size_t i)> f) {
|
||||||
|
d.fill(f);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Same as \a fill().
|
||||||
|
//! \~russian Тоже самое что и \a fill().
|
||||||
|
//! \~\sa \a fill(), \a resize()
|
||||||
|
inline PIByteArray & assign(uchar e = 0) {return fill(e);}
|
||||||
|
|
||||||
|
//! \~english First does `resize(new_size)` then `fill(e)`.
|
||||||
|
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
|
||||||
|
//! \~\sa \a fill(), \a resize()
|
||||||
|
inline PIByteArray & assign(size_t new_size, uchar e) {
|
||||||
|
resize(new_size);
|
||||||
|
return fill(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 PIByteArray & resize(size_t new_size, uchar e = 0) {
|
||||||
|
d.resize(new_size, e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 PIByteArray & resize(size_t new_size, std::function<uchar(size_t i)> f) {
|
||||||
|
d.resize(new_size, f);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Return resized byte array
|
||||||
|
//! \~russian Возвращает копию байтового массива с измененным размером
|
||||||
|
PIByteArray resized(uint new_size) const {
|
||||||
|
PIByteArray ret(new_size);
|
||||||
|
memcpy(ret.data(), data(), new_size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 PIByteArray & reserve(size_t new_size) {
|
||||||
|
d.reserve(new_size);
|
||||||
|
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 PIByteArray & insert(size_t index, uchar e = 0) {
|
||||||
|
d.insert(index, 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 PIByteArray & insert(size_t index, const PIByteArray & v) {
|
||||||
|
d.insert(index, v.d);
|
||||||
|
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 PIByteArray & insert(size_t index, std::initializer_list<uchar> init_list) {
|
||||||
|
d.insert(index, init_list);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Removes `count` elements from the middle of the array, starting at `index` position.
|
||||||
|
//! \~russian Удаляет элементы из массива, начиная с позиции `index` в количестве `count`.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a resize(), \a insert(), \a removeOne(), \a removeAll(), \a removeWhere()
|
||||||
|
inline PIByteArray & remove(size_t index, size_t count = 1) {
|
||||||
|
d.remove(index, count);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 d.getRange(index, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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() на месте переставляет элементы массива,
|
||||||
|
//! на котором он был вызван, изменяет массив и возвращает ссылку на него.
|
||||||
|
//! Первый элемент массива становится последним, а последний — первым.
|
||||||
|
//! \~\sa \a reversed()
|
||||||
|
inline PIByteArray & reverse() {
|
||||||
|
d.reverse();
|
||||||
|
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 PIByteArray reversed() const {
|
||||||
|
PIByteArray 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 PIByteArray & enlarge(ssize_t add_size, uchar e = 0) {
|
||||||
|
d.enlarge(add_size, e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Remove no more than one element equal `e`.
|
||||||
|
//! \~russian Удаляет первый элемент, который равен элементу `e`.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a remove(), \a removeAll(), \a removeWhere()
|
||||||
|
inline PIByteArray & removeOne(uchar e) {
|
||||||
|
d.removeOne(e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Remove all elements equal `e`.
|
||||||
|
//! \~russian Удаляет все элементы, равные элементу `e`.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
|
||||||
|
inline PIByteArray & removeAll(uchar e) {
|
||||||
|
d.removeAll(e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Remove all elements in the array
|
||||||
|
//! passes the test implemented by the provided function `test`.
|
||||||
|
//! \~russian Удаляет все элементы, удовлетворяющие условию,
|
||||||
|
//! заданному в передаваемой функции `test`.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
|
||||||
|
inline PIByteArray & removeWhere(std::function<bool(uchar e)> test) {
|
||||||
|
d.removeWhere(test);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Appends the given element `e` to the end of the array.
|
||||||
|
//! \~russian Добавляет элемент `e` в конец массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english If size() is less than capacity(), which is most often
|
||||||
|
//! then the addition will be very fast.
|
||||||
|
//! In any case, the addition is fast and does not depend on the size of the array.
|
||||||
|
//! If the new size() is greater than capacity()
|
||||||
|
//! then all iterators and references
|
||||||
|
//! (including the past-the-end iterator) are invalidated.
|
||||||
|
//! Otherwise only the past-the-end iterator is invalidated.
|
||||||
|
//! \~russian Если size() меньше capacity(), что часто бывает,
|
||||||
|
//! то добавление будет очень быстрым.
|
||||||
|
//! В любом случае добавление быстрое и не зависит от размера массива.
|
||||||
|
//! Если новый size() больше, чем capacity(),
|
||||||
|
//! то все итераторы и указатели становятся нерабочими.
|
||||||
|
//! В противном случае все, кроме итераторов, указывающих на конец массива,
|
||||||
|
//! остаются в рабочем состоянии.
|
||||||
|
//! \~\sa \a push_front(), \a append(), \a prepend(), \a insert()
|
||||||
|
inline PIByteArray & push_back(uchar e) {
|
||||||
|
d.push_back(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 PIByteArray & push_back(std::initializer_list<uchar> init_list) {
|
||||||
|
d.push_back(init_list);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Appends the given array `v` to the end of the array.
|
||||||
|
//! \~russian Добавляет массив `v` в конец массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Overloaded function.
|
||||||
|
//! \~russian Перегруженая функция.
|
||||||
|
//! \~\sa \a push_back()
|
||||||
|
inline PIByteArray & push_back(const PIByteArray & v) {
|
||||||
|
d.push_back(v.d);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Help struct to store/restore custom blocks of data to/from PIByteArray
|
//! \~english Add to the end data "data" with size "size"
|
||||||
struct RawData {
|
//! \~russian Добавляет в конец массива данные по указателю "data" размером "size"
|
||||||
friend PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v);
|
PIByteArray & push_back(const void * data_, int size_) {uint ps = size(); enlarge(size_); memcpy(data(ps), data_, size_); return *this;}
|
||||||
friend PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v);
|
|
||||||
public:
|
|
||||||
//! Constructs data block
|
|
||||||
RawData(void * data = 0, int size = 0) {d = data; s = size;}
|
|
||||||
RawData(const RawData & o) {d = o.d; s = o.s;}
|
|
||||||
//! Constructs data block
|
|
||||||
RawData(const void * data, const int size) {d = const_cast<void * >(data); s = size;}
|
|
||||||
RawData & operator =(const RawData & o) {d = o.d; s = o.s; return *this;}
|
|
||||||
private:
|
|
||||||
void * d;
|
|
||||||
int s;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Return resized byte array
|
//! \~english Appends the given element `e` to the begin of the array.
|
||||||
PIByteArray resized(uint new_size) const {PIByteArray ret(new_size); memcpy(ret.data(), data(), new_size); return ret;}
|
//! \~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 Если в начале массива имеется свободное место,
|
||||||
|
//! что часто бывает, то добавление будет очень быстрым.
|
||||||
|
//! В любом случае добавление быстрое и не зависит от размера массива.
|
||||||
|
//! Если в начале массива нет свободного места,
|
||||||
|
//! то все итераторы и указатели становятся нерабочими.
|
||||||
|
//! В противном случае все, кроме итераторов указывающих, на начало массива,
|
||||||
|
//! остаются в рабочем состоянии.
|
||||||
|
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
|
||||||
|
inline PIByteArray & push_front(uchar e) {
|
||||||
|
d.push_front(e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
//! Convert data to Base 64 and return this byte array
|
//! \~english Appends the given array `v` to the begin of the array.
|
||||||
|
//! \~russian Добавляет массив `v` в начало массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Overloaded function.
|
||||||
|
//! \~russian Перегруженая функция.
|
||||||
|
//! \~\sa \a push_front()
|
||||||
|
inline PIByteArray & push_front(const PIByteArray & v) {
|
||||||
|
d.push_front(v.d);
|
||||||
|
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 PIByteArray & push_front(std::initializer_list<uchar> init_list) {
|
||||||
|
d.push_front(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 Если в начале массива имеется свободное место,
|
||||||
|
//! что часто бывает, то добавление будет очень быстрым.
|
||||||
|
//! В любом случае добавление быстрое и не зависит от размера массива.
|
||||||
|
//! Если в начале массива нет свободного места,
|
||||||
|
//! то все итераторы и указатели становятся нерабочими.
|
||||||
|
//! В противном случае все, кроме итераторов указывающих, на начало массива,
|
||||||
|
//! остаются в рабочем состоянии.
|
||||||
|
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
|
||||||
|
inline PIByteArray & prepend(uchar e) {
|
||||||
|
d.prepend(e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Appends the given array `v` to the begin of the array.
|
||||||
|
//! \~russian Добавляет массив `v` в начало массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Overloaded function.
|
||||||
|
//! \~russian Перегруженая функция.
|
||||||
|
//! \~\sa \a prepend()
|
||||||
|
inline PIByteArray & prepend(const PIByteArray & v) {
|
||||||
|
d.prepend(v.d);
|
||||||
|
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 PIByteArray & prepend(std::initializer_list<uchar> init_list) {
|
||||||
|
d.prepend(init_list);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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 Удаление элемента с конца выполняется очень быстро
|
||||||
|
//! и не зависит от размера массива.
|
||||||
|
//! \~\sa \a pop_front(), \a take_back(), \a take_front()
|
||||||
|
inline PIByteArray & pop_back() {
|
||||||
|
d.pop_back();
|
||||||
|
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 Удаление элемента с начала выполняется дольше, чем с конца.
|
||||||
|
//! Это время прямопропорционально размеру массива.
|
||||||
|
//! При удалении элемента все итераторы и указатели становятся нерабочими.
|
||||||
|
//! \~\sa \a pop_back(), \a take_back(), \a take_front()
|
||||||
|
inline PIByteArray & pop_front() {
|
||||||
|
d.pop_front();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Remove one element from the end of the array and return it.
|
||||||
|
//! \~russian Удаляет один элемент с начала массива и возвращает его.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
|
||||||
|
inline uchar take_back() {
|
||||||
|
return d.take_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Remove one element from the begining of the array and return it.
|
||||||
|
//! \~russian Удаляет один элемент с конца массива и возвращает его.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
|
||||||
|
inline uchar take_front() {
|
||||||
|
return d.take_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Returns a new array with all elements
|
||||||
|
//! that pass the test implemented by the provided function `test`.
|
||||||
|
//! \~russian Возвращает новый массив со всеми элементами,
|
||||||
|
//! прошедшими проверку, задаваемую в передаваемой функции `test`.
|
||||||
|
//! \~\details
|
||||||
|
//! \~\code
|
||||||
|
//! PIByteArray v{3, 2, 5, 2, 7};
|
||||||
|
//! PIByteArray v2 = v.filter([](const uchar & i){return i > 2;});
|
||||||
|
//! piCout << v2; // {3, 5, 7}
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a map(), \a any(), \a every()
|
||||||
|
inline PIByteArray filter(std::function<bool(const uchar & e)> test) const {
|
||||||
|
return PIByteArray(d.filter(test));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Execute function `void f(const uchar & e)` for every element in array.
|
||||||
|
//! \~russian Выполняет функцию `void f(const uchar & e)` для каждого элемента массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~russian Не позволяет изменять элементы массива.
|
||||||
|
//! Для редактирования элементов используйте функцию вида `void f(uchar & e)`.
|
||||||
|
//! \~english Does not allow changing array elements.
|
||||||
|
//! To edit elements, use the function like `void f(T & e)`
|
||||||
|
//! \~\code
|
||||||
|
//! PIByteArray v{1, 2, 3, 4, 5};
|
||||||
|
//! int s = 0;
|
||||||
|
//! v.forEach([&s](const uchar & 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 uchar & e)> f) const {
|
||||||
|
d.forEach(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Execute function `void f(uchar & e)` for every element in array.
|
||||||
|
//! \~russian Выполняет функцию `void f(uchar & e)` для каждого элемента массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Overloaded function.
|
||||||
|
//! Allows you to change the elements of the array.
|
||||||
|
//! \~russian Перегруженая функция.
|
||||||
|
//! Позволяет изменять элементы массива.
|
||||||
|
//! \~\code
|
||||||
|
//! PIByteArray v{1, 2, 3, 4, 5};
|
||||||
|
//! v.forEach([](uchar & e){e++;});
|
||||||
|
//! piCout << v; // {2, 3, 4, 5, 6}
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a filter(), \a map(), \a reduce(), \a any(), \a every()
|
||||||
|
inline PIByteArray & forEach(std::function<void(uchar & e)> f) {
|
||||||
|
d.forEach(f);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Сreates a new array populated with the results
|
||||||
|
//! of calling a provided function `ST f(const uchar & e)` on every element in the calling array.
|
||||||
|
//! \~russian Создаёт новый массив с результатом вызова указанной функции
|
||||||
|
//! `ST f(const T & e)` для каждого элемента массива.
|
||||||
|
//! \~\details
|
||||||
|
//! \~english Calls a provided function`ST f(const uchar & e)`
|
||||||
|
//! once for each element in an array, in order,
|
||||||
|
//! and constructs a new array from the results.
|
||||||
|
//! \~russian Метод `map` вызывает переданную функцию `ST f(const uchar & e)`
|
||||||
|
//! один раз для каждого элемента в порядке их появления
|
||||||
|
//! и конструирует новый массив из результатов её вызова.
|
||||||
|
//! \~\code
|
||||||
|
//! PIByteArray v{0x31, 0x0A, 0xFF};
|
||||||
|
//! PIStringList sl = v.map<PIString>([](const uchar & i){return PIString::fromNumber(i, 16);});
|
||||||
|
//! piCout << sl; {"31", "A", "FF"}
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a forEach(), \a reduce()
|
||||||
|
template <typename ST>
|
||||||
|
inline PIDeque<ST> map(std::function<ST(const uchar & e)> f) const {
|
||||||
|
return d.map<ST>(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~english Applies the function `ST f(const uchar & e, const ST & acc)`
|
||||||
|
//! to each element of the array (from left to right), returns one value.
|
||||||
|
//! \~russian Применяет функцию `ST f(const uchar & 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 uchar & 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 uchar & e, const ST & acc)`,
|
||||||
|
//! выполняющаяся для каждого элемента массива.
|
||||||
|
//! Она принимает два аргумента:
|
||||||
|
//! * **e** - текущий элемент массива
|
||||||
|
//! * **acc** - аккумулятор, аккумулирующий значение
|
||||||
|
//! которое возвращает эта функция после посещения очередного элемента
|
||||||
|
//!
|
||||||
|
//! \param initial _опциональный_ Объект,
|
||||||
|
//! используемый в качестве второго аргумента при первом вызове функции `f`.
|
||||||
|
//!
|
||||||
|
//! \~\code
|
||||||
|
//! PIByteArray v{1, 2, 3, 4, 5};
|
||||||
|
//! PIString s = v.reduce<PIString>([](const uchar & e, const PIString & acc){return acc + PIString::fromNumber(e);});
|
||||||
|
//! piCout << s; // "12345"
|
||||||
|
//! \endcode
|
||||||
|
//! \~\sa \a forEach(), \a map()
|
||||||
|
template <typename ST>
|
||||||
|
inline ST reduce(std::function<ST(const uchar & e, const ST & acc)> f, const ST & initial = ST()) const {
|
||||||
|
return d.reduce<ST>(f, initial);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \~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,39 +1064,70 @@ 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 Appends the given elements to the end of the array.
|
||||||
//! sum all bytes, add 1, inverse
|
//! \~russian Добавляет элементы в конец массива.
|
||||||
//! Pseudocode:
|
//! \~\details
|
||||||
//! sum += at(i);
|
//! \~english Overloaded function.
|
||||||
//! return ~(sum + 1)
|
//! Appends the given elements from
|
||||||
uchar checksumPlain8() const;
|
//! [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 PIByteArray & append(std::initializer_list<uchar> init_list) {
|
||||||
|
d.append(init_list);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
//! Returns 32-bit checksum
|
//! \~english Returns 8-bit checksum
|
||||||
//! sum all bytes multiplyed by index+1, add 1, inverse
|
//! \~russian Возвращает 8-битную контрольную сумму
|
||||||
//! Pseudocode:
|
uchar checksumPlain8(bool inverse = true) const;
|
||||||
//! sum += at(i) * (i + 1);
|
|
||||||
//! return ~(sum + 1)
|
|
||||||
uint checksumPlain32() const;
|
|
||||||
|
|
||||||
//! Returns hash
|
//! \~english Returns 32-bit checksum
|
||||||
|
//! \~russian Возвращает 32-битную контрольную сумму
|
||||||
|
uint checksumPlain32(bool inverse = true) const;
|
||||||
|
|
||||||
|
//! \~english Returns 8-bit checksum CRC-8
|
||||||
|
//! \~russian Возвращает 8-битную контрольную сумму CRC-8
|
||||||
|
uchar checksumCRC8() const;
|
||||||
|
|
||||||
|
//! \~english Returns 16-bit checksum CRC-16
|
||||||
|
//! \~russian Возвращает 16-битную контрольную сумму CRC-16
|
||||||
|
ushort checksumCRC16() const;
|
||||||
|
|
||||||
|
//! \~english Returns 32-bit checksum CRC-32
|
||||||
|
//! \~russian Возвращает 32-битную контрольную сумму CRC-32
|
||||||
|
uint checksumCRC32() const;
|
||||||
|
|
||||||
|
//! \~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> & o) {resize(o.size()); memcpy(data(), o.data(), o.size());}
|
||||||
|
|
||||||
PIByteArray & operator =(const PIByteArray & o) {if (this == &o) return *this; clear(); append(o); return *this;}
|
PIByteArray & operator =(const PIByteArray & o) {if (this == &o) return *this; clear(); append(o); return *this;}
|
||||||
|
|
||||||
@@ -172,450 +1137,128 @@ 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);
|
||||||
|
|
||||||
|
|
||||||
class StreamRef {
|
bool binaryStreamAppendImp(const void * d_, size_t s) {
|
||||||
public:
|
append(d_, s);
|
||||||
StreamRef(PIByteArray & s): ba(s) {}
|
return true;
|
||||||
operator PIByteArray&() {return ba;}
|
}
|
||||||
private:
|
bool binaryStreamTakeImp(void * d_, size_t s) {
|
||||||
PIByteArray & ba;
|
size_t rs = size();
|
||||||
};
|
if (rs > s) rs = s;
|
||||||
|
memcpy(d_, data(), rs);
|
||||||
|
remove(0, rs);
|
||||||
|
return rs == s;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t binaryStreamSizeImp() const {return size();}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PIDeque<uchar> d;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \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);
|
||||||
|
|
||||||
|
|
||||||
|
//! \relatesalso PIBinaryStream
|
||||||
|
//! \~english Store operator.
|
||||||
// store operators for basic types
|
//! \~russian Оператор сохранения.
|
||||||
|
BINARY_STREAM_WRITE(PIByteArray) {
|
||||||
|
s.binaryStreamAppend((int)v.size_s());
|
||||||
//! \relatesalso PIByteArray @brief Store operator
|
s.binaryStreamAppend(v.data(), v.size());
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const bool v) {s.push_back(v); return s;}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const char v) {s.push_back(v); return s;}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const uchar v) {s.push_back(v); return s;}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator for any trivial copyable type
|
|
||||||
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray::StreamRef operator <<(PIByteArray & s, const T & v) {
|
|
||||||
int os = s.size_s();
|
|
||||||
s.enlarge(sizeof(v));
|
|
||||||
memcpy(s.data(os), &v, sizeof(v));
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator, see \ref PIByteArray_sec1 for details
|
//! \relatesalso PIBinaryStream
|
||||||
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v);
|
//! \~english Restore operator.
|
||||||
|
//! \~russian Оператор извлечения.
|
||||||
//! \relatesalso PIByteArray @brief Store operator, see \ref PIByteArray_sec1 for details
|
BINARY_STREAM_READ(PIByteArray) {
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {
|
v.resize(s.binaryStreamTakeInt());
|
||||||
int os = s.size_s();
|
s.binaryStreamTake(v.data(), v.size());
|
||||||
if (v.s > 0) {
|
|
||||||
s.enlarge(v.s);
|
|
||||||
memcpy(s.data(os), v.d, v.s);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator for PIVector of any trivial copyable type
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
|
|
||||||
s << int(v.size_s());
|
|
||||||
int os = s.size_s();
|
|
||||||
if (v.size_s() > 0) {
|
|
||||||
s.enlarge(v.size_s()*sizeof(T));
|
|
||||||
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
|
|
||||||
s << int(v.size_s());
|
|
||||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator for PIDeque of any trivial copyable type
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
|
|
||||||
s << int(v.size_s());
|
|
||||||
int os = s.size_s();
|
|
||||||
if (v.size_s() > 0) {
|
|
||||||
s.enlarge(v.size_s()*sizeof(T));
|
|
||||||
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
|
|
||||||
s << int(v.size_s());
|
|
||||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator for PIVector2D of any trivial copyable type
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
|
|
||||||
s << int(v.rows()) << int(v.cols());
|
|
||||||
int os = s.size_s();
|
|
||||||
if (v.size_s() > 0) {
|
|
||||||
s.enlarge(v.size_s()*sizeof(T));
|
|
||||||
memcpy(s.data(os), v.data(), v.size_s()*sizeof(T));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
|
|
||||||
s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIBitArray & v) {s << v.size_ << v.data_; return s;}
|
|
||||||
|
|
||||||
//! \relatesalso PIPair @brief Store operator
|
|
||||||
template<typename Type0, typename Type1>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIPair<Type0, Type1> & v) {s << v.first << v.second; return s;}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// restore operators for basic types
|
|
||||||
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, bool & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator
|
|
||||||
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
|
|
||||||
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray::StreamRef operator >>(PIByteArray & s, T & v) {
|
|
||||||
if (s.size() < sizeof(v)) {
|
|
||||||
printf("error with %s\n", _TYPENAME_(T));
|
|
||||||
assert(s.size() >= sizeof(v));
|
|
||||||
}
|
|
||||||
memcpy((void*)(&v), s.data(), sizeof(v));
|
|
||||||
s.remove(0, sizeof(v));
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator, see \ref PIByteArray_sec1 for details
|
|
||||||
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator, see \ref PIByteArray_sec1 for details
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIByteArray::RawData v) {
|
|
||||||
if (s.size_s() < v.s) {
|
|
||||||
printf("error with RawData %d < %d\n", (int)s.size_s(), v.s);
|
|
||||||
assert(s.size_s() >= v.s);
|
|
||||||
}
|
|
||||||
if (v.s > 0) {
|
|
||||||
memcpy((void*)(v.d), s.data(), v.s);
|
|
||||||
s.remove(0, v.s);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator for PIVector of any trivial copyable type
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
printf("error with PIVector<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
}
|
|
||||||
int sz; s >> sz;
|
|
||||||
v._resizeRaw(sz);
|
|
||||||
if (sz > 0) {
|
|
||||||
memcpy(v.data(), s.data(), sz*sizeof(T));
|
|
||||||
s.remove(0, sz*sizeof(T));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
printf("error with PIVector<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
}
|
|
||||||
int sz; s >> sz;
|
|
||||||
v.resize(sz);
|
|
||||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator for PIDeque of any trivial copyable type
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
}
|
|
||||||
int sz; s >> sz;
|
|
||||||
v._resizeRaw(sz);
|
|
||||||
if (sz > 0) {
|
|
||||||
memcpy(v.data(), s.data(), sz*sizeof(T));
|
|
||||||
s.remove(0, sz*sizeof(T));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
}
|
|
||||||
int sz; s >> sz;
|
|
||||||
v.resize(sz);
|
|
||||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator for PIVector2D of any trivial copyable type
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if< std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
|
|
||||||
if (s.size_s() < 8) {
|
|
||||||
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 8);
|
|
||||||
}
|
|
||||||
int r, c; s >> r >> c;
|
|
||||||
v._resizeRaw(r, c);
|
|
||||||
int sz = r*c;
|
|
||||||
if (sz > 0) {
|
|
||||||
memcpy(v.data(), s.data(), sz*sizeof(T));
|
|
||||||
s.remove(0, sz*sizeof(T));
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
template<typename T,
|
|
||||||
typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0,
|
|
||||||
typename std::enable_if<!std::is_same<decltype(std::declval<PIByteArray&>() << std::declval<const T &>()), PIByteArray::StreamRef>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
|
|
||||||
if (s.size_s() < 8) {
|
|
||||||
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 8);
|
|
||||||
}
|
|
||||||
int r,c;
|
|
||||||
PIVector<T> tmp;
|
|
||||||
s >> r >> c >> tmp;
|
|
||||||
v = PIVector2D<T>(r, c, tmp);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIBitArray & v) {assert(s.size_s() >= 8); s >> v.size_ >> v.data_; return s;}
|
|
||||||
|
|
||||||
//! \relatesalso PIPair @brief Restore operator
|
|
||||||
template<typename Type0, typename Type1>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIPair<Type0, Type1> & v) {s >> v.first >> v.second; return s;}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// store operators for complex types
|
|
||||||
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator for PIVector of any compound type
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector<T> & v) {
|
|
||||||
s << int(v.size_s());
|
|
||||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator for PIDeque of any compound type
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIDeque<T> & v) {
|
|
||||||
s << int(v.size_s());
|
|
||||||
for (uint i = 0; i < v.size(); ++i) s << v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Store operator for PIVector2D of any compound type
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIVector2D<T> & v) {
|
|
||||||
s << int(v.rows()) << int(v.cols()) << v.toPlainVector();
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// restore operators for complex types
|
|
||||||
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator for PIVector of any compound type
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector<T> & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
printf("error with PIVector<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
}
|
|
||||||
int sz; s >> sz;
|
|
||||||
v.resize(sz);
|
|
||||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator for PIDeque of any compound type
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIDeque<T> & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
printf("error with PIDeque<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
}
|
|
||||||
int sz; s >> sz;
|
|
||||||
v.resize(sz);
|
|
||||||
for (int i = 0; i < sz; ++i) s >> v[i];
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \relatesalso PIByteArray @brief Restore operator for PIVector2D of any compound type
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIVector2D<T> & v) {
|
|
||||||
if (s.size_s() < 8) {
|
|
||||||
printf("error with PIVecto2Dr<%s>\n", _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 8);
|
|
||||||
}
|
|
||||||
int r,c;
|
|
||||||
PIVector<T> tmp;
|
|
||||||
s >> r >> c >> tmp;
|
|
||||||
v = PIVector2D<T>(r, c, tmp);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// other types
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Key, typename T>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const PIMap<Key, T> & v) {
|
|
||||||
s << int(v.pim_index.size_s());
|
|
||||||
for (uint i = 0; i < v.size(); ++i)
|
|
||||||
s << int(v.pim_index[i].index) << v.pim_index[i].key;
|
|
||||||
s << v.pim_content;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Key, typename T>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, PIMap<Key, T> & v) {
|
|
||||||
if (s.size_s() < 4) {
|
|
||||||
printf("error with PIMap<%s, %s>\n", _TYPENAME_(Key), _TYPENAME_(T));
|
|
||||||
assert(s.size_s() >= 4);
|
|
||||||
}
|
|
||||||
int sz; s >> sz; v.pim_index.resize(sz);
|
|
||||||
int ind = 0;
|
|
||||||
for (int i = 0; i < sz; ++i) {
|
|
||||||
s >> ind >> v.pim_index[i].key;
|
|
||||||
v.pim_index[i].index = ind;
|
|
||||||
}
|
|
||||||
s >> v.pim_content;
|
|
||||||
if (v.pim_content.size_s() != v.pim_index.size_s()) {
|
|
||||||
piCout << "Warning: loaded invalid PIMap, clear";
|
|
||||||
v.clear();
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator <<(PIByteArray & s, const T & ) {
|
|
||||||
static_assert(std::is_trivially_copyable<T>::value, "[PIByteArray] Error: using undeclared operator << for complex type!");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename std::enable_if<!std::is_trivially_copyable<T>::value, int>::type = 0>
|
|
||||||
inline PIByteArray & operator >>(PIByteArray & s, T & ) {
|
|
||||||
static_assert(std::is_trivially_copyable<T>::value, "[PIByteArray] Error: using undeclared operator >> for complex type!");
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! \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 +1269,4 @@ template <typename T> T piDeserialize(const PIByteArray & data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef _TYPENAME_
|
|
||||||
|
|
||||||
|
|
||||||
#endif // PIBYTEARRAY_H
|
#endif // PIBYTEARRAY_H
|
||||||
|
|||||||
@@ -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,13 +353,13 @@ PIChar PIChar::toLower() const {
|
|||||||
return PIChar(wc);
|
return PIChar(wc);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
return PIChar(towlower(ch));
|
return PIChar((ushort)towlower(ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PICout operator <<(PICout s, const PIChar & v) {
|
PICout operator <<(PICout s, const PIChar & v) {
|
||||||
s.space();
|
s.space();
|
||||||
s.setControl(0, true);
|
s.saveAndSetControls(0);
|
||||||
if (v.isAscii()) s << char(v.ch);
|
if (v.isAscii()) s << char(v.ch);
|
||||||
else {
|
else {
|
||||||
#ifdef PIP_ICU
|
#ifdef PIP_ICU
|
||||||
@@ -377,17 +375,11 @@ 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.restoreControls();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
@@ -91,7 +117,7 @@ int PIChunkStream::read() {
|
|||||||
last_id = readVInt(*data_);
|
last_id = readVInt(*data_);
|
||||||
last_data.resize(readVInt(*data_));
|
last_data.resize(readVInt(*data_));
|
||||||
//piCout << last_id << last_data.size();
|
//piCout << last_id << last_data.size();
|
||||||
(*data_) >> PIByteArray::RawData(last_data.data(), last_data.size_s());
|
(*data_) >> PIMemoryBlock(last_data.data(), last_data.size_s());
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -99,15 +125,14 @@ int PIChunkStream::read() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int PIChunkStream::peekVInt(Version version_, PIByteArray * data_, int pos, PIByteArray & hdr, uint & ret) {
|
int PIChunkStream::peekVInt(Version version_, uchar * data_, int sz, uint & ret) {
|
||||||
switch (version_) {
|
switch (version_) {
|
||||||
case Version_1:
|
case Version_1:
|
||||||
memcpy(&ret, data_->data(pos), 4);
|
memcpy(&ret, data_, 4);
|
||||||
return 4;
|
return 4;
|
||||||
case Version_2: {
|
case Version_2: {
|
||||||
|
PIByteArray hdr(data_, piMini(4, sz));
|
||||||
hdr.resize(4);
|
hdr.resize(4);
|
||||||
hdr.fill(uchar(0));
|
|
||||||
memcpy(hdr.data(), data_->data(pos), piMini(4, data_->size_s() - pos));
|
|
||||||
uchar hsz = 0;
|
uchar hsz = 0;
|
||||||
ret = readVInt(hdr, &hsz);
|
ret = readVInt(hdr, &hsz);
|
||||||
return hsz;
|
return hsz;
|
||||||
@@ -127,13 +152,16 @@ void PIChunkStream::replaceChunk(int id, const PIByteArray & v) {
|
|||||||
pos.length = v.size_s();
|
pos.length = v.size_s();
|
||||||
if (size_mod != 0) {
|
if (size_mod != 0) {
|
||||||
auto it = data_map.makeIterator();
|
auto it = data_map.makeIterator();
|
||||||
while (it.next())
|
while (it.next()) {
|
||||||
if (it.valueRef().start > pos.start)
|
if (it.value().start > pos.start) {
|
||||||
it.valueRef().start += size_mod;
|
it.value().start += size_mod;
|
||||||
if (size_mod > 0)
|
}
|
||||||
|
}
|
||||||
|
if (size_mod > 0) {
|
||||||
data_->insert(pos.start, PIByteArray(size_mod));
|
data_->insert(pos.start, PIByteArray(size_mod));
|
||||||
else
|
} else {
|
||||||
data_->remove(pos.start, -size_mod);
|
data_->remove(pos.start, -size_mod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
memcpy(data_->data(pos.start - pos.size_bytes), nsba.data(), nsba.size());
|
memcpy(data_->data(pos.start - pos.size_bytes), nsba.data(), nsba.size());
|
||||||
pos.start += nsba.size_s() - pos.size_bytes;
|
pos.start += nsba.size_s() - pos.size_bytes;
|
||||||
@@ -146,10 +174,9 @@ void PIChunkStream::readAll() {
|
|||||||
if (!data_) return;
|
if (!data_) return;
|
||||||
int pos = 0, sz = data_->size_s(), hsz = 0;
|
int pos = 0, sz = data_->size_s(), hsz = 0;
|
||||||
uint csz = 0, cid = 0;
|
uint csz = 0, cid = 0;
|
||||||
PIByteArray hdr;
|
|
||||||
while (pos < sz) {
|
while (pos < sz) {
|
||||||
pos += peekVInt((Version)version_, data_, pos, hdr, cid);
|
pos += peekVInt((Version)version_, data_->data(pos), data_->size_s() - pos, cid);
|
||||||
hsz = peekVInt((Version)version_, data_, pos, hdr, csz);
|
hsz = peekVInt((Version)version_, data_->data(pos), data_->size_s() - pos, csz);
|
||||||
pos += hsz;
|
pos += hsz;
|
||||||
data_map[cid] = CacheEntry(pos, csz, hsz);
|
data_map[cid] = CacheEntry(pos, csz, hsz);
|
||||||
pos += csz;
|
pos += csz;
|
||||||
@@ -167,8 +194,7 @@ bool PIChunkStream::extract(PIByteArray & data, bool read_all) {
|
|||||||
if (tmp_data.size_s() < 4) return false;
|
if (tmp_data.size_s() < 4) return false;
|
||||||
data_ = &tmp_data;
|
data_ = &tmp_data;
|
||||||
_init();
|
_init();
|
||||||
if (read_all)
|
if (read_all) readAll();
|
||||||
readAll();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,19 +208,27 @@ void PIChunkStream::_init() {
|
|||||||
if ((v & 0x80) == 0x80) {
|
if ((v & 0x80) == 0x80) {
|
||||||
v &= 0x7f;
|
v &= 0x7f;
|
||||||
switch (v) {
|
switch (v) {
|
||||||
case 2: version_ = (uchar)Version_2; data_->pop_front(); first_byte_taken = true; break;
|
case 2:
|
||||||
default: version_ = Version_1; break;
|
version_ = (uchar)Version_2;
|
||||||
|
data_->pop_front();
|
||||||
|
first_byte_taken = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
version_ = Version_1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
version_ = Version_1;
|
version_ = Version_1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint PIChunkStream::readVInt(PIByteArray & s, uchar * bytes_cnt) {
|
uint PIChunkStream::readVInt(PIByteArray & s, uchar * bytes_cnt) {
|
||||||
if (s.isEmpty()) return 0;
|
if (s.isEmpty()) return 0;
|
||||||
uchar bytes[4]; s >> bytes[0];
|
uchar bytes[4];
|
||||||
uchar abc = 0;
|
uchar abc;
|
||||||
|
s >> bytes[0];
|
||||||
for (abc = 0; abc < 3; ++abc) {
|
for (abc = 0; abc < 3; ++abc) {
|
||||||
uchar mask = (0x80 >> abc);
|
uchar mask = (0x80 >> abc);
|
||||||
if ((bytes[0] & mask) == mask) {
|
if ((bytes[0] & mask) == mask) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user