3 Commits

Author SHA1 Message Date
Бычков Анлрей
e85b11a233 PIMap via pipair, fix tests 2022-05-26 18:07:44 +03:00
Бычков Анлрей
831adf3fc9 some new tests 2022-05-25 18:52:19 +03:00
Бычков Анлрей
a18f461ce3 pimap tests 2022-05-24 18:40:06 +03:00
387 changed files with 32968 additions and 50560 deletions

View File

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

View File

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

1
.gitignore vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(PIP)
set(PIP_MAJOR 4)
set(PIP_MINOR 3)
set(PIP_REVISION 0)
set(PIP_SUFFIX )
set(PIP_COMPANY SHS)
set(PIP_DOMAIN org.SHS)
project(pip)
set(pip_MAJOR 2)
set(pip_MINOR 39)
set(pip_REVISION 0)
set(pip_SUFFIX )
set(pip_COMPANY SHS)
set(pip_DOMAIN org.SHS)
set(GIT_CMAKE_DIR)
if (NOT DEFINED SHSTKPROJECT)
@@ -17,7 +17,7 @@ cmake_minimum_required(VERSION 2.8.2)
project(cmake-download NONE)
include(ExternalProject)
ExternalProject_Add(cmake
GIT_REPOSITORY https://git.shstk.ru/SHS/cmake.git
GIT_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\"
@@ -53,8 +53,7 @@ include(CheckFunctionExists)
include(PIPMacros)
include(SHSTKMacros)
shstk_begin_project(PIP)
set(PIP_VERSION "${PIP_VERSION}" CACHE STRING "")
shstk_begin_project(pip PIP)
set(_ICU_DEFAULT OFF)
if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE))
@@ -62,28 +61,17 @@ if((NOT DEFINED WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT DEFINED APPLE
endif()
set(PIP_DLL_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE STRING "")
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_DEBUG ON)
else()
set(PIP_BUILD_DEBUG OFF)
endif()
# Options
option(ICU "ICU support for convert codepages" ${_ICU_DEFAULT})
option(STD_IOSTREAM "Building with std iostream operators support" OFF)
option(INTROSPECTION "Build with introspection" OFF)
option(TESTS "Build tests and perform their before install step" ${PIP_BUILD_DEBUG})
option(TESTS "Build tests and perform their before install step" OFF)
option(COVERAGE "Build project with coverage info" OFF)
set(PIP_UTILS 1)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_STANDARD 11)
shstk_is_parent_exists(_pe)
if (_pe)
set(BUILDING_pip 1 PARENT_SCOPE)
set(pip_ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE)
endif()
# Basic
set(PIP_MODULES)
@@ -96,7 +84,7 @@ set(PIP_UTILS_LIST)
set(PIP_TESTS_LIST)
set(PIP_EXPORTS)
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua")
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;cloud;lua")
foreach(_m ${PIP_SRC_MODULES})
set(PIP_MSG_${_m} "no")
endforeach()
@@ -108,7 +96,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
set(CRES)
file(GLOB_RECURSE CPPS "libs/${NAME}/*.cpp" "libs/${NAME}/*.c")
file(GLOB_RECURSE HS "libs/${NAME}/*.h")
file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h" "libs/${NAME}/3rd/*.h")
file(GLOB_RECURSE PHS "libs/${NAME}/*_p.h")
file(GLOB_RECURSE RES "libs/${NAME}/*.conf")
if (NOT "x${PHS}" STREQUAL "x")
list(REMOVE_ITEM HS ${PHS})
@@ -117,14 +105,9 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
file(GLOB_RECURSE ASRC "${SOURCES}/*.cpp" "${SOURCES}/*.c")
list(APPEND CPPS ${ASRC})
endif()
#message("${NAME} HS = ${HS}")
list(APPEND HDRS ${HS})
list(APPEND PHDRS ${PHS})
if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
else()
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${CPPS} ${HS} ${PHS})
endif()
set(_target "pip_${NAME}")
set(_libs "${LIBS}")
if ("${NAME}" STREQUAL "main")
@@ -135,11 +118,11 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
string(TOUPPER "${_target}" DEF_NAME)
set(PIP_MSG_${NAME} "yes${MSG}")
import_version(${_target} PIP)
set_deploy_property(${_target} ${PIP_LIB_TYPE}
import_version(${_target} pip)
set_deploy_property(${_target} ${pip_LIB_TYPE}
LABEL "${LABEL}"
FULLNAME "${PIP_DOMAIN}.${_target}"
COMPANY "${PIP_COMPANY}"
FULLNAME "${pip_DOMAIN}.${_target}"
COMPANY "${pip_COMPANY}"
INFO "Platform-Independent Primitives")
make_rc(${_target} _RC)
@@ -156,7 +139,7 @@ macro(pip_module NAME LIBS LABEL INCLUDES SOURCES MSG)
pip_resources(CRES "${RES}")
endif()
add_definitions(-D${DEF_NAME})
add_library(${_target} ${PIP_LIB_TYPE} ${CPPS} ${CRES} ${_RC} ${HS} ${PHS})
add_library(${_target} ${pip_LIB_TYPE} ${CPPS} ${CRES} ${_RC})
target_include_directories(${_target} PUBLIC ${PIP_INCLUDES})
if (NOT "x${RES}" STREQUAL "x")
add_dependencies(${_target} pip_rc)
@@ -251,11 +234,26 @@ if(PIP_MATH_YN)
add_definitions(-DPIP_MATH_YN)
endif()
# Check if RT timers exists
set(CMAKE_REQUIRED_INCLUDES time.h)
set(CMAKE_REQUIRED_LIBRARIES )
if((NOT DEFINED ENV{QNX_HOST}) AND (NOT APPLE) AND (NOT WIN32) AND (NOT DEFINED ANDROID_PLATFORM) AND (NOT PIP_FREERTOS))
list(APPEND LIBS_MAIN rt)
set(CMAKE_REQUIRED_LIBRARIES rt)
endif()
CHECK_FUNCTION_EXISTS(timer_create PIP_TIMER_RT_0)
CHECK_FUNCTION_EXISTS(timer_settime PIP_TIMER_RT_1)
CHECK_FUNCTION_EXISTS(timer_delete PIP_TIMER_RT_2)
# Check if build debug version
if (PIP_BUILD_DEBUG)
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(PIP_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Wall")
add_definitions(-DPIP_DEBUG)
else()
set(PIP_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -Wall")
endif()
@@ -309,6 +307,15 @@ list(APPEND HDRS ${_PIP_DEFS_FILE})
#message("${_PIP_DEFS_CHANGED}")
# Check if RT timers exists
if(PIP_TIMER_RT_0 AND PIP_TIMER_RT_1 AND PIP_TIMER_RT_2)
set(PIP_TIMERS "Thread, ThreadRT, Pool")
add_definitions(-DPIP_TIMER_RT)
else()
set(PIP_TIMERS "Thread, Pool")
endif()
# Add main library
if(APPLE)
@@ -319,27 +326,23 @@ if ((NOT DEFINED SHSTKPROJECT) AND (DEFINED ANDROID_PLATFORM))
#message("${ANDROID_SYSTEM_LIBRARY_PATH}/usr/include")
#message("${ANDROID_NDK}/sysroot/usr/include")
endif()
if(NOT PIP_FREERTOS)
if(WIN32)
if(WIN32)
if(${C_COMPILER} STREQUAL "cl.exe")
else()
list(APPEND LIBS_MAIN ws2_32 iphlpapi psapi cfgmgr32 setupapi)
endif()
else()
else()
list(APPEND LIBS_MAIN dl)
if(DEFINED ENV{QNX_HOST})
list(APPEND LIBS_MAIN socket)
else()
if (NOT DEFINED ANDROID_PLATFORM)
list(APPEND LIBS_MAIN pthread util)
if (NOT APPLE)
list(APPEND LIBS_MAIN rt)
endif()
endif()
endif()
endif()
endif()
endif()
set(PIP_LIBS)
if(PIP_FREERTOS)
set(PIP_LIBS ${LIBS_MAIN})
@@ -396,7 +399,6 @@ if (NOT CROSSTOOLS)
pip_find_lib(sodium)
if(sodium_FOUND)
pip_module(crypt "sodium" "PIP crypt support" "" "" "")
pip_module(client_server "pip_io_utils" "PIP client-server helper" "" "" "")
pip_module(cloud "pip_io_utils" "PIP cloud support" "" "" "")
endif()
@@ -446,16 +448,17 @@ if (NOT CROSSTOOLS)
endif()
if (NOT "x${MINGW_INCLUDE}" STREQUAL "x")
list(APPEND CMAKE_INCLUDE_PATH "${MINGW_INCLUDE}")
endif()
find_package(OpenCL QUIET) #OpenCL_VERSION_STRING
if(OpenCL_FOUND)
set(_opencl_lib OpenCL::OpenCL)
if(${CMAKE_VERSION} VERSION_LESS "3.7.0")
target_link_libraries(_opencl_lib OpenCL)
endif()
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}")
if(APPLE)
set(_opencl_inc "${OpenCL_INCLUDE_DIRS}/Headers")
endif()
pip_module(opencl "OpenCL" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
pip_module(opencl "${_opencl_lib}" "PIP OpenCL support" "${_opencl_inc}" "" " (${OpenCL_VERSION_STRING})")
endif()
@@ -478,18 +481,14 @@ if (NOT CROSSTOOLS)
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
list(APPEND HDRS ${_lua_src_hdr})
# Test program
if(PIP_UTILS)
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp" "ccm.h" "ccm.cpp")
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp")
#target_link_libraries(pip_plugin pip)
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_io_utils pip_client_server)
if(sodium_FOUND)
add_executable(pip_cloud_test "main_picloud_test.cpp")
target_link_libraries(pip_cloud_test pip_cloud)
endif()
target_link_libraries(pip_test pip)
endif()
else()
@@ -563,7 +562,6 @@ if(NOT PIP_FREERTOS)
add_subdirectory("utils/code_model_generator")
add_subdirectory("utils/resources_compiler")
add_subdirectory("utils/deploy_tool")
add_subdirectory("utils/value_tree_translator")
if(PIP_UTILS AND (NOT CROSSTOOLS))
add_subdirectory("utils/system_test")
add_subdirectory("utils/udp_file_transfer")
@@ -590,18 +588,18 @@ if ((NOT PIP_FREERTOS) AND (NOT CROSSTOOLS))
find_package(Doxygen)
if(DOXYGEN_FOUND)
set(DOXY_DEFINES "${PIP_EXPORTS}")
foreach (_m "console" "usb" "compress" "crypt" "client_server" "cloud" "fftw" "opencl" "io_utils" "lua")
foreach (_m "console" "usb" "compress" "crypt" "cloud" "fftw" "opencl" "io_utils" "lua")
string(TOUPPER "${_m}" _mdef)
list(APPEND DOXY_DEFINES "PIP_${_mdef}_EXPORT")
endforeach()
set(DOXY_PROJECT_NUMBER "${PIP_VERSION}")
set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"")
set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${PIP_VERSION}\"")
set(DOXY_PROJECT_NUMBER "${pip_VERSION}")
set(DOXY_QHP_CUST_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_QHP_SECT_FILTER_ATTRS "\"PIP ${pip_VERSION}\"")
set(DOXY_EXAMPLE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/examples\"")
set(DOXY_IMAGE_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/images\"")
set(DOXY_LOGO_PATH "\"${CMAKE_CURRENT_SOURCE_DIR}/doc/pip.png\"")
set(DOXY_EXCLUDE "\"${CMAKE_CURRENT_SOURCE_DIR}/libs/lua/3rd\"")
set(DOXY_DOMAIN "${PIP_DOMAIN}.${PROJECT_NAME}.doc")
set(DOXY_DOMAIN "${pip_DOMAIN}.${PROJECT_NAME}.doc")
if ("x${DOC_LANG}" STREQUAL "x")
set(DOXY_OUTPUT_LANGUAGE English)
set(DOXY_OUTPUT_DIR en)
@@ -647,9 +645,9 @@ endmacro()
list(REMOVE_ITEM LIBS_STATUS ${PIP_MODULES})
message("----------PIP----------")
message(" Version: ${PIP_VERSION} ")
message(" Linkage: ${PIP_LIB_TYPE_MSG}")
message(" Type : ${CMAKE_BUILD_TYPE}")
message(" Version: ${pip_VERSION} ")
message(" Linkage: ${pip_LIB_TYPE_MSG}")
message(" Type : ${pip_BUILD_TYPE}")
if (NOT LOCAL)
message(" Install: \"${CMAKE_INSTALL_PREFIX}\"")
else()
@@ -661,6 +659,7 @@ message("")
message(" Options:")
message(" std::iostream: ${PIP_STD_IOSTREAM}")
message(" ICU strings : ${PIP_ICU}")
message(" Timer types : ${PIP_TIMERS}")
message(" Introspection: ${PIP_INTROSPECTION}")
message(" Coverage : ${PIP_COVERAGE}")
if(INTROSPECTION)

View File

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

View File

@@ -9,7 +9,6 @@ Create imported targets:
* PIP::FFTW
* PIP::OpenCL
* PIP::IOUtils
* PIP::ClientServer
* PIP::Cloud
* PIP::Lua
@@ -21,11 +20,16 @@ main library
cmake_policy(SET CMP0011 NEW) # don`t affect includer policies
include(SHSTKMacros)
shstk_set_find_dirs(PIP)
shstk_set_find_dirs(pip)
if(PIP_DIR)
list(APPEND pip_LIBDIR "${PIP_DIR}/lib")
list(APPEND pip_INCDIR "${PIP_DIR}/include/pip")
list(APPEND pip_BINDIR "${PIP_DIR}/bin")
endif()
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua")
set(__libs "usb;crypt;console;fftw;compress;io_utils;opencl;cloud;lua")
if (BUILDING_PIP)
if (BUILDING_pip)
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua")
#set(_bins "pip_cmg;pip_rc;deploy_tool")
#get_target_property(_path pip BINARY_DIR)
@@ -36,20 +40,20 @@ if (BUILDING_PIP)
set(PIP_FOUND ON CACHE BOOL "")
else()
find_library(PIP_LIBRARY pip HINTS ${PIP_LIBDIR})
find_library(PIP_LIBRARY pip HINTS ${pip_LIBDIR})
foreach (_l ${__libs})
find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${PIP_LIBDIR})
find_library(PIP_LIBRARY_${_l} pip_${_l} HINTS ${pip_LIBDIR})
endforeach()
endif()
if (BUILDING_PIP AND (NOT CMAKE_CROSSCOMPILING))
if (BUILDING_pip AND (NOT CMAKE_CROSSCOMPILING))
set(PIP_CMG "$<TARGET_FILE_DIR:pip_cmg>/$<TARGET_FILE_NAME:pip_cmg>" CACHE STRING "")
set(PIP_RC "$<TARGET_FILE_DIR:pip_rc>/$<TARGET_FILE_NAME:pip_rc>" CACHE STRING "")
set(PIP_DEPLOY_TOOL "$<TARGET_FILE_DIR:deploy_tool>/$<TARGET_FILE_NAME:deploy_tool>" CACHE STRING "")
else()
find_program(PIP_CMG pip_cmg${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
find_program(PIP_RC pip_rc${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
find_program(PIP_DEPLOY_TOOL deploy_tool${PIP_BINEXT} HINTS ${PIP_BINDIR} ${PIP_FIND_PROGRAM_ARG})
find_program(PIP_CMG pip_cmg${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_RC pip_rc${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
find_program(PIP_DEPLOY_TOOL deploy_tool${pip_BINEXT} HINTS ${pip_BINDIR} ${pip_FIND_PROGRAM_ARG})
endif()
if (NOT PIP_LIBRARY)
if(PIP_FIND_REQUIRED)
@@ -59,7 +63,7 @@ if (NOT PIP_LIBRARY)
endif()
set(_PIP_LIBRARY_PATH_ "${PIP_LIBRARY}")
set(_PIP_ADD_LIBS_ "")
if (NOT BUILDING_PIP)
if (NOT BUILDING_pip)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
find_library(DL_LIBRARY dl)
list(APPEND PIP_LIBRARY ${DL_LIBRARY})
@@ -76,9 +80,9 @@ if (NOT BUILDING_PIP)
endif()
endif()
if (NOT BUILDING_PIP)
shstk_find_header(PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}")
set(PIP_INCLUDES "${PIP_INCLUDES}" CACHE STRING "")
if (NOT BUILDING_pip)
shstk_find_header(pip PIP "pip_version.h" "${_PIP_LIBRARY_PATH_}")
set(PIP_INCLUDES "${pip_INCLUDES}" CACHE STRING "")
endif()
if(PIP_FIND_VERSION VERSION_GREATER PIP_VERSION)
message(FATAL_ERROR "PIP version ${PIP_VERSION} is available, but ${PIP_FIND_VERSION} requested!")
@@ -91,7 +95,6 @@ set(__module_fftw FFTW )
set(__module_compress Compress )
set(__module_opencl OpenCL )
set(__module_io_utils IOUtils )
set(__module_client_server ClientServer)
set(__module_cloud Cloud )
set(__module_lua Lua )
@@ -101,15 +104,14 @@ foreach (_l ${__libs})
set(__libs_${_l} "")
endforeach()
set(__deps_io_utils "PIP::Crypt" )
set(__deps_client_server "PIP::IOUtils")
set(__deps_io_utils "PIP::Crypt")
set(__deps_cloud "PIP::IOUtils")
if (BUILDING_PIP)
if (BUILDING_pip)
if (NOT SET_TARGETS_PIP)
set(SET_TARGETS_PIP ON CACHE BOOL "")
if (NOT SET_TARGETS_pip)
set(SET_TARGETS_pip ON CACHE BOOL "")
#message("create aliases")
if((NOT TARGET PIP) AND PIP_LIBRARY)
#message("alias PIP = pip")
@@ -131,7 +133,7 @@ else()
add_library(PIP UNKNOWN IMPORTED)
set_target_properties(PIP PROPERTIES
IMPORTED_LOCATION "${_PIP_LIBRARY_PATH_}"
INTERFACE_INCLUDE_DIRECTORIES "${PIP_INCLUDES}"
INTERFACE_INCLUDE_DIRECTORIES "${pip_INCLUDES}"
INTERFACE_LINK_LIBRARIES "${_PIP_ADD_LIBS_}")
#message("imported PIP = ${PIP_LIBRARY}")
endif()

View File

@@ -2282,7 +2282,7 @@ EXTERNAL_GROUPS = YES
# be listed.
# The default value is: YES.
EXTERNAL_PAGES = NO
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
* direct output to console (\a PICout)
* containers (\a PIVector, \a PIDeque, \a PIVector2D, \a PIStack, \a PIQueue, \a PIMap, \a PISet)
* byte array (\a PIByteArray)
* serialization (\a PIBinaryStream, \a PITextStream, \a PIIOBinaryStream, \a PIIOTextStream, \a PIChunkStream, \a PIJSON)
* serialization (\a PIChunkStream)
* string (\a PIConstChars, \a PIString, \a PIStringList)
* base object (events and handlers) (\a PIObject)
* multithreading
@@ -57,7 +57,7 @@
* общение с консолью (\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 PIChunkStream)
* строка (\a PIConstChars, \a PIString, \a PIStringList)
* базовый объект (события и обработчики) (\a PIObject)
* многопоточность

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,50 +0,0 @@
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piclientserver_config.h"
#include "piclientserver_client_base.h"
void PIClientServer::Config::setPacketSign(ushort sign) {
packet_sign = sign;
}
void PIClientServer::Config::setPacketSize(int bytes) {
packet_size = bytes;
}
void PIClientServer::Config::enableSymmetricEncryption(const PIByteArray & key) {
crypt_key = key;
}
void PIClientServer::Config::apply(ClientBase * client) {
auto & s(client->stream);
s.setPacketSign(packet_sign);
s.setMaxPacketSize(packet_size);
if (crypt_key.isNotEmpty()) {
s.setCryptEnabled(true);
s.setCryptKey(crypt_key);
} else
s.setCryptEnabled(false);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,9 +18,8 @@
*/
#include "picloudtcp.h"
#include "pichunkstream.h"
#include "picrypt.h"
#include "pichunkstream.h"
#include "piethernet.h"
#include "pistreampacker.h"
@@ -33,8 +32,8 @@ PICloud::TCP::Header::Header() {
}
PICloud::TCP::TCP(PIStreamPacker * s): streampacker(s) {
streampacker->setMaxPacketSize(63 * 1024);
PICloud::TCP::TCP(PIStreamPacker * s) : streampacker(s) {
streampacker->setMaxPacketSize(63*1024);
}
void PICloud::TCP::setRole(PICloud::TCP::Role r) {
@@ -44,8 +43,7 @@ void PICloud::TCP::setRole(PICloud::TCP::Role r) {
void PICloud::TCP::setServerName(const PIString & server_name_) {
server_name = server_name_;
suuid =
PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
suuid = PICrypt::hash(PIByteArray(server_name_.data(), server_name_.size()), (const unsigned char *)hash_cloud_key, sizeof(hash_cloud_key));
}
@@ -55,7 +53,7 @@ PIString PICloud::TCP::serverName() const {
void PICloud::TCP::sendStart() {
// piCout << "sendStart";
//piCout << "sendStart";
if (suuid.size() != PICrypt::sizeHash()) {
piCout << "PICloud ERROR, server not set, invoke setServerName first";
return;
@@ -64,9 +62,9 @@ void PICloud::TCP::sendStart() {
PIByteArray ba;
ba << header;
ba.append(suuid);
// mutex_send.lock();
//mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
//mutex_send.unlock();
}
@@ -74,9 +72,9 @@ void PICloud::TCP::sendConnected(uint client_id) {
header.type = PICloud::TCP::Connect;
PIByteArray ba;
ba << header << client_id;
// mutex_send.lock();
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
// mutex_send.unlock();
}
@@ -84,9 +82,9 @@ void PICloud::TCP::sendDisconnected(uint client_id) {
header.type = PICloud::TCP::Disconnect;
PIByteArray ba;
ba << header << client_id;
// mutex_send.lock();
// mutex_send.lock();
streampacker->send(ba);
// mutex_send.unlock();
// mutex_send.unlock();
}
@@ -95,7 +93,7 @@ int PICloud::TCP::sendData(const PIByteArray & data) {
PIByteArray ba;
ba << header;
ba.append(data);
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
// piCout << "[PICloud::TCP] sendData" << ba.toHex();
mutex_send.lock();
streampacker->send(ba);
mutex_send.unlock();
@@ -134,8 +132,7 @@ PIPair<PICloud::TCP::Type, PICloud::TCP::Role> PICloud::TCP::parseHeader(PIByteA
PICloud::TCP::Header hdr;
ba >> hdr;
if (hdr.version != header.version) {
piCout << "[PICloud]"
<< "invalid PICloud::TCP version!";
piCout << "[PICloud]" << "invalid PICloud::TCP version!";
return ret;
}
ret.first = (Type)hdr.type;
@@ -171,14 +168,14 @@ PIByteArray PICloud::TCP::parseConnect_d(PIByteArray & ba) {
uint PICloud::TCP::parseConnect(PIByteArray & ba) {
uint ret = 0;
uint ret;
ba >> ret;
return ret;
}
uint PICloud::TCP::parseDisconnect(PIByteArray & ba) {
uint ret = 0;
uint ret;
ba >> ret;
return ret;
}

View File

@@ -38,16 +38,14 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
ulong sz = zba.size();
ret = compress2(zba.data(), &sz, ba.data(), ba.size(), level);
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory";
piCout << "[PICompress]" << "Error: invalid input or not enought memory";
return ba;
}
zba.resize(sz);
zba << ullong(ba.size());
return zba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return ba;
}
@@ -55,10 +53,9 @@ PIByteArray piCompress(const PIByteArray & ba, int level) {
PIByteArray piDecompress(const PIByteArray & zba) {
#ifdef PIP_COMPRESS
ullong sz = 0;
ullong sz;
if (zba.size() < sizeof(ullong)) {
piCout << "[PICompress]"
<< "Error: invalid input";
piCout << "[PICompress]" << "Error: invalid input";
return zba;
}
PIByteArray ba(zba.data(zba.size() - sizeof(ullong)), sizeof(ullong));
@@ -68,14 +65,12 @@ PIByteArray piDecompress(const PIByteArray & zba) {
ulong s = sz;
ret = uncompress(ba.data(), &s, zba.data(), zba.size());
if (ret != Z_OK) {
piCout << "[PICompress]"
<< "Error: invalid input or not enought memory";
piCout << "[PICompress]" << "Error: invalid input or not enought memory";
return zba;
}
return ba;
#else
piCout << "[PICompress]"
<< "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
piCout << "[PICompress]" << "Warning: PICompress is disabled, to enable install zlib library and build pip_compress library";
#endif
return zba;
}

View File

@@ -17,16 +17,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "piscreen.h"
#include "piincludes_p.h"
#include "piliterals_time.h"
#ifndef WINDOWS
# include <fcntl.h>
# include <sys/ioctl.h>
# include <fcntl.h>
# include <termios.h>
#else
# include <wincon.h>
# include <wingdi.h>
# include <wincon.h>
# ifndef COMMON_LVB_UNDERSCORE
# define COMMON_LVB_UNDERSCORE 0x8000
# endif
@@ -53,18 +51,6 @@ PRIVATE_DEFINITION_END(PIScreen::SystemConsole)
PIScreen::SystemConsole::SystemConsole() {
width = height = pwidth = pheight = 0;
mouse_x = mouse_y = -1;
}
PIScreen::SystemConsole::~SystemConsole() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
void PIScreen::SystemConsole::begin() {
int w, h;
#ifdef WINDOWS
PRIVATE->ulcoord.X = 0;
@@ -88,6 +74,18 @@ void PIScreen::SystemConsole::begin() {
# endif
#endif
resize(w, h);
}
PIScreen::SystemConsole::~SystemConsole() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
#endif
}
void PIScreen::SystemConsole::begin() {
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
@@ -95,7 +93,6 @@ void PIScreen::SystemConsole::begin() {
PRIVATE->bc.Y = 0;
#endif
clear();
clearScreen();
hideCursor();
}
@@ -160,7 +157,7 @@ void PIScreen::SystemConsole::resize(int w, int h) {
void PIScreen::SystemConsole::print() {
if (mouse_x >= 0 && mouse_x < width && mouse_y >= 0 && mouse_y < height) {
/// cells[mouse_y][mouse_x].format.flags ^= Inverse;
///cells[mouse_y][mouse_x].format.flags ^= Inverse;
}
#ifdef WINDOWS
PRIVATE->srect = PRIVATE->sbi.srWindow;
@@ -191,7 +188,7 @@ void PIScreen::SystemConsole::print() {
PRIVATE->chars[k].Char.AsciiChar = c.symbol.toConsole1Byte();
PRIVATE->chars[k].Attributes = attributes(c);
}
// piCout << "draw" << dw << dh;
//piCout << "draw" << dw << dh;
PRIVATE->bs.X = dw;
PRIVATE->bs.Y = dh;
PRIVATE->srect.Left += dx0;
@@ -230,7 +227,7 @@ void PIScreen::SystemConsole::print() {
if (!s.isEmpty()) {
moveTo(si, sj);
PICout::stdoutPIString(s);
// printf("%s", s.data());
//printf("%s", s.data());
s.clear();
}
}
@@ -242,18 +239,14 @@ void PIScreen::SystemConsole::print() {
#ifdef WINDOWS
# define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
# define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
#define FOREGROUND_MASK (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)
ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
WORD attr = PRIVATE->dattr;
if (c.format.flags & Bold)
attr |= FOREGROUND_INTENSITY;
else
attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline)
attr |= COMMON_LVB_UNDERSCORE;
else
attr &= ~COMMON_LVB_UNDERSCORE;
if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY;
else attr &= ~FOREGROUND_INTENSITY;
if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE;
else attr &= ~COMMON_LVB_UNDERSCORE;
switch (c.format.color_char) {
case Black: attr = (attr & ~FOREGROUND_MASK); break;
case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break;
@@ -282,8 +275,8 @@ ushort PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) {
}
return attr;
}
# undef FOREGROUND_MASK
# undef BACKGROUND_MASK
#undef FOREGROUND_MASK
#undef BACKGROUND_MASK
void PIScreen::SystemConsole::getWinCurCoord() {
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->csbi);
@@ -298,8 +291,7 @@ void PIScreen::SystemConsole::clearLine() {
void PIScreen::SystemConsole::newLine() {
getWinCurCoord();
PRIVATE->ccoord.X = 0;
PRIVATE->ccoord.Y++;
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
}
#else // WINDOWS
@@ -325,10 +317,10 @@ PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) {
case Yellow: ts += PIStringAscii(";43"); break;
case White: ts += PIStringAscii(";47"); break;
}
if ((c.format.flags & Bold) == Bold) ts += PIStringAscii(";1");
if ((c.format.flags & Bold ) == Bold ) ts += PIStringAscii(";1");
if ((c.format.flags & Underline) == Underline) ts += PIStringAscii(";4");
if ((c.format.flags & Blink) == Blink) ts += PIStringAscii(";5");
if ((c.format.flags & Inverse) == Inverse) ts += PIStringAscii(";7");
if ((c.format.flags & Blink ) == Blink ) ts += PIStringAscii(";5");
if ((c.format.flags & Inverse ) == Inverse ) ts += PIStringAscii(";7");
return ts + 'm';
}
#endif // WINDOWS
@@ -365,16 +357,8 @@ void PIScreen::SystemConsole::clearScreen() {
void PIScreen::SystemConsole::clearScreenLower() {
#ifdef WINDOWS
getWinCurCoord();
FillConsoleOutputAttribute(PRIVATE->hOut,
PRIVATE->dattr,
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut,
' ',
width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X,
PRIVATE->ccoord,
&PRIVATE->written);
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
#else
printf("\e[0m\e[J");
#endif
@@ -399,7 +383,7 @@ void PIScreen::SystemConsole::showCursor() {
}
// PIScreen
PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawer_(console.cells), root("rootTile") {
setName("screen");
@@ -407,19 +391,20 @@ PIScreen::PIScreen(bool startNow, PIKbdListener::KBFunc slot): PIThread(), drawe
needLockRun(true);
mouse_ = false;
ret_func = slot;
tile_focus = tile_dialog = nullptr;
tile_focus = tile_dialog = 0;
root.screen = this;
listener = new PIKbdListener(key_eventS, this, startNow);
CONNECT1(void, PIKbdListener::MouseEvent, listener, mouseEvent, this, mouse_event);
CONNECT1(void, PIKbdListener::WheelEvent, listener, wheelEvent, this, wheel_event);
CONNECTU(listener, mouseEvent, this, mouse_event);
CONNECTU(listener, wheelEvent, this, wheel_event);
if (startNow) start();
}
PIScreen::~PIScreen() {
if (isRunning()) stop();
PIThread::waitForFinish(100_ms);
listener->waitForFinish(100_ms);
if (isRunning())
stop();
PIThread::waitForFinish(10);
listener->waitForFinish(10);
delete listener;
}
@@ -437,12 +422,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
return;
*/
PIScreenTile * rtile = rootTile();
if (tile_dialog) rtile = tile_dialog;
if (tile_dialog)
rtile = tile_dialog;
bool used = nextFocus(rtile, key);
if (used) return;
if (!used && tile_focus) {
if (tile_focus->visible) {
if (tile_focus->keyEvent(key)) return;
if (tile_focus->keyEvent(key))
return;
}
}
if (ret_func != 0) ret_func(key, data_);
@@ -450,14 +437,14 @@ void PIScreen::key_event(PIKbdListener::KeyEvent key) {
}
PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile *> ret;
PIVector<PIScreenTile * > PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
PIVector<PIScreenTile * > ret;
if (!mouse_ || !e) return ret;
console.mouse_x = e->x;
console.mouse_y = e->y;
PIVector<PIScreenTile *> tl = tilesUnderMouse(e->x, e->y);
PIVector<PIScreenTile * > tl = tilesUnderMouse(e->x, e->y);
bool ff = false;
piForeachR(PIScreenTile * t, tl) {
piForeachR (PIScreenTile * t, tl) {
if (!ff) {
if (t->focus_flags[FocusOnMouse] && (e->action == PIKbdListener::MouseButtonPress)) {
t->setFocus();
@@ -468,13 +455,14 @@ PIVector<PIScreenTile *> PIScreen::prepareMouse(PIKbdListener::MouseEvent * e) {
ff = true;
}
}
}
return tl;
}
PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile *> ret;
PIVector<PIScreenTile * > PIScreen::tilesUnderMouse(int x, int y) {
PIVector<PIScreenTile * > ret;
if (x < 0 || x >= console.width || y < 0 || y >= console.height) return ret;
PIScreenTile * ct = tile_dialog ? tile_dialog : rootTile();
bool f = true;
@@ -488,25 +476,27 @@ PIVector<PIScreenTile *> PIScreen::tilesUnderMouse(int x, int y) {
void PIScreen::mouse_event(PIKbdListener::MouseEvent me) {
PIVector<PIScreenTile *> tl = prepareMouse(&me);
PIVector<PIScreenTile * > tl = prepareMouse(&me);
if (tl.isEmpty()) return;
piForeachR(PIScreenTile * t, tl)
piForeachR (PIScreenTile * t, tl)
if (t->mouseEvent(me)) break;
}
void PIScreen::wheel_event(PIKbdListener::WheelEvent we) {
PIVector<PIScreenTile *> tl = prepareMouse(&we);
PIVector<PIScreenTile * > tl = prepareMouse(&we);
if (tl.isEmpty()) return;
piForeachR(PIScreenTile * t, tl)
piForeachR (PIScreenTile * t, tl)
if (t->wheelEvent(we)) break;
}
bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
PIVector<PIScreenTile *> vtl = rt->children(true), ftl;
piForeach(PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus]) ftl << t;
PIVector<PIScreenTile*> vtl = rt->children(true), ftl;
piForeach (PIScreenTile * t, vtl) {
if (t->focus_flags[CanHasFocus])
ftl << t;
}
int ind = -1;
for (int i = 0; i < ftl.size_s(); ++i)
@@ -514,15 +504,18 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
ind = i;
break;
}
if (ind < 0) tile_focus = 0;
if (ind < 0)
tile_focus = 0;
if (ftl.isEmpty())
tile_focus = 0;
else {
if (tile_focus)
if (!tile_focus->visible) tile_focus = 0;
if (!tile_focus->visible)
tile_focus = 0;
int next = tile_focus ? 0 : 1;
if (tile_focus) {
if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab) next = 1;
if (tile_focus->focus_flags[NextByTab] && key.key == PIKbdListener::Tab)
next = 1;
if (tile_focus->focus_flags[NextByArrowsHorizontal]) {
if (key.key == PIKbdListener::LeftArrow) next = -1;
if (key.key == PIKbdListener::RightArrow) next = 1;
@@ -532,10 +525,10 @@ bool PIScreen::nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key) {
if (key.key == PIKbdListener::DownArrow) next = 1;
}
}
// piCout << ftl.size() << ind << next;
//piCout << ftl.size() << ind << next;
if (next != 0) {
PIVector<PIScreenTile *> tl = rt->children();
piForeach(PIScreenTile * t, tl)
PIVector<PIScreenTile*> tl = rt->children();
piForeach (PIScreenTile * t, tl)
t->has_focus = false;
if (!ftl.isEmpty()) {
ind += next;
@@ -557,19 +550,22 @@ void PIScreen::tileEventInternal(PIScreenTile * t, TileEvent e) {
void PIScreen::tileRemovedInternal(PIScreenTile * t) {
if (tile_dialog == t) tile_dialog = 0;
if (tile_dialog == t)
tile_dialog = 0;
}
void PIScreen::tileSetFocusInternal(PIScreenTile * t) {
PIScreenTile * rt = rootTile();
if (tile_dialog) rt = tile_dialog;
PIVector<PIScreenTile *> tl = rt->children(), ftl;
piForeach(PIScreenTile * i, tl)
if (tile_dialog)
rt = tile_dialog;
PIVector<PIScreenTile*> tl = rt->children(), ftl;
piForeach (PIScreenTile * i, tl)
i->has_focus = false;
tile_focus = t;
if (!tile_focus) return;
if (tile_focus->focus_flags[CanHasFocus]) tile_focus->has_focus = true;
if (tile_focus->focus_flags[CanHasFocus])
tile_focus->has_focus = true;
}
@@ -591,14 +587,8 @@ void PIScreen::waitForFinish() {
}
void PIScreen::start(bool wait) {
PIThread::start(25_Hz);
if (wait) waitForFinish();
}
void PIScreen::stop(bool clear) {
PIThread::stopAndWait();
PIThread::stop(true);
if (clear) console.clearScreen();
#ifndef WINDOWS
fflush(0);
@@ -630,13 +620,8 @@ void PIScreen::run() {
tile_dialog->height_ = sh;
tile_dialog->layout();
int dx = tile_dialog->x_ - 1, dy = tile_dialog->y_ - 1, dw = tile_dialog->width_, dh = tile_dialog->height_;
drawer_.drawFrame(dx,
dy,
dx + dw + 1,
dy + dh + 1,
(Color)tile_dialog->back_format.color_char,
(Color)tile_dialog->back_format.color_back,
(CharFlags)tile_dialog->back_format.flags);
drawer_.drawFrame(dx, dy, dx + dw + 1, dy + dh + 1, (Color)tile_dialog->back_format.color_char,
(Color)tile_dialog->back_format.color_back, (CharFlags)tile_dialog->back_format.flags);
tile_dialog->drawEventInternal(&drawer_);
}
console.print();
@@ -650,8 +635,10 @@ void PIScreen::end() {
PIScreenTile * PIScreen::tileByName(const PIString & name) {
PIVector<PIScreenTile *> tl(tiles());
piForeach(PIScreenTile * t, tl)
if (t->name() == name) return t;
PIVector<PIScreenTile*> tl(tiles());
piForeach (PIScreenTile * t, tl)
if (t->name() == name)
return t;
return 0;
}

View File

@@ -22,14 +22,21 @@
using namespace PIScreenTypes;
TileVars::TileVars(const PIString & n): PIScreenTile(n) {
TileVars::TileVars(const PIString &n) : PIScreenTile(n) {
alignment = Left;
}
void TileVars::sizeHint(int & w, int & h) const {}
void TileVars::sizeHint(int &w, int &h) const {
void TileVars::drawEvent(PIScreenDrawer * d) {}
}
void TileVars::drawEvent(PIScreenDrawer *d) {
}
PIScreenConsoleTile::PIScreenConsoleTile() {}
PIScreenConsoleTile::PIScreenConsoleTile() {
}

View File

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

View File

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

View File

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

View File

@@ -16,20 +16,17 @@
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 "piterminal.h"
#include "piincludes_p.h"
#include "piliterals_time.h"
#include "piterminal.h"
#include "pisharedmemory.h"
#ifndef MICRO_PIP
# ifdef WINDOWS
# include <wincon.h>
#ifdef WINDOWS
# include <windows.h>
# include <wingdi.h>
# include <wincon.h>
# include <winuser.h>
# else
#else
# include "piprocess.h"
# include <csignal>
# include <fcntl.h>
# include <sys/ioctl.h>
@@ -49,12 +46,12 @@
# else
# define HAS_FORKPTY
# endif
# endif
#endif
// extern PIMutex PICout::__mutex__;
//extern PIMutex PICout::__mutex__;
# ifdef WINDOWS
#ifdef WINDOWS
# define PIPE_BUFFER_SIZE 1024
enum PITerminalAuxMessageType {
mtKey = 1,
@@ -68,22 +65,22 @@ struct PITerminalAuxData {
int size_y;
int cells_size;
};
# else
#else
# define BUFFER_SIZE 4096
enum DECType {
CKM = 1
};
# endif
#endif
PRIVATE_DEFINITION_START(PITerminal)
# ifdef WINDOWS
#ifdef WINDOWS
PISharedMemory * shm;
HANDLE hConBuf;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
HANDLE pipe;
# else
#else
PIString shell;
PIByteArray read_buf, tmp_buf;
PIScreenTypes::CellFormat cur_format, line_format;
@@ -95,21 +92,21 @@ PRIVATE_DEFINITION_START(PITerminal)
PIString esc_seq;
bool is_esc_seq, last_read;
PIMap<int, bool> DEC;
PIVector<PIVector<PIScreenTypes::Cell>> cells_save;
# endif
PIVector<PIVector<PIScreenTypes::Cell> > cells_save;
#endif
PRIVATE_DEFINITION_END(PITerminal)
# ifdef WINDOWS
#ifdef WINDOWS
int writePipe(HANDLE pipe, const PIByteArray & ba) {
DWORD wrote[2];
int sz = ba.size_s();
WriteFile(pipe, &sz, 4, &(wrote[0]), 0);
WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0);
// piCout << "send" << ba.size_s();
//piCout << "send" << ba.size_s();
return int(wrote[0] + wrote[1]);
}
# endif
#endif
PITerminal::PITerminal(): PIThread() {
@@ -119,39 +116,40 @@ PITerminal::PITerminal(): PIThread() {
cursor_x = cursor_y = 0;
dsize_x = 80;
dsize_y = 24;
# ifdef WINDOWS
#ifdef WINDOWS
PRIVATE->shm = 0;
# endif
#endif
}
PITerminal::~PITerminal() {
if (isRunning()) stop();
PIThread::waitForFinish(1_s);
if (isRunning())
stop();
PIThread::waitForFinish(10);
destroy();
# ifdef WINDOWS
#ifdef WINDOWS
if (PRIVATE->shm) delete PRIVATE->shm;
# endif
#endif
}
void PITerminal::write(const PIByteArray & d) {
# ifdef WINDOWS
#ifdef WINDOWS
PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke;
for (int i = 0; i < d.size_s(); ++i)
ke << PIKbdListener::KeyEvent(d[i]);
msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg);
# else
#else
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return;
// ssize_t wrote = 0;
// wrote =
//ssize_t wrote = 0;
//wrote =
::write(PRIVATE->fd, d.data(), d.size_s());
// piCout << "wrote" << wrote << d;
# endif
//piCout << "wrote" << wrote << d;
# endif
#endif
cursor_tm.reset();
cursor_blink = true;
}
@@ -159,16 +157,15 @@ void PITerminal::write(const PIByteArray & d) {
void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) {
PIByteArray ba;
# ifdef WINDOWS
#ifdef WINDOWS
switch (k) {
case PIKbdListener::Tab: ba << uchar('\t'); break;
case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break;
case PIKbdListener::Space: ba << uchar(' '); break;
default: break;
}
// piCout << "write" << ba.size();
if (!ba.isEmpty())
write(ba);
//piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba);
else {
PIByteArray msg;
PIVector<PIKbdListener::KeyEvent> ke;
@@ -176,7 +173,7 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg);
}
# else
#else
int term = PRIVATE->term_type;
int flags = 0;
switch (k) {
@@ -188,8 +185,7 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::UpArrow:
case PIKbdListener::DownArrow:
case PIKbdListener::RightArrow:
case PIKbdListener::LeftArrow:
if (PRIVATE->DEC.value(CKM, false)) flags = 1;
case PIKbdListener::LeftArrow: if (PRIVATE->DEC.value(CKM, false)) flags = 1;
/*case PIKbdListener::Home: //break;
case PIKbdListener::End: //break;
case PIKbdListener::PageUp: //ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break;
@@ -210,18 +206,18 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
case PIKbdListener::F12: //break;
*/
default: {
// piCout << flags;
// int mod = 0;
//piCout << flags;
//int mod = 0;
if (m[PIKbdListener::Shift]) m |= 1;
if (m[PIKbdListener::Alt]) m |= 2;
if (m[PIKbdListener::Ctrl]) m |= 4;
for (int i = 0;; ++i) {
for (int i = 0; ; ++i) {
const PIKbdListener::EscSeq & e(PIKbdListener::esc_seq[i]);
if (!e.seq) break;
// piCout << "search" << rc[1] << esc_seq[i].seq;
//piCout << "search" << rc[1] << esc_seq[i].seq;
if (e.key == k && e.mod == m) {
if (((e.vt & term) == term) || (((e.flags & flags) == flags) && (flags != 0))) {
// piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e");
//piCout << "found key" << PIString(e.seq).replaceAll("\e", "\\e");
PIByteArray d = ("\e" + PIString(e.seq)).toByteArray();
write(d);
break;
@@ -230,35 +226,35 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers
}
} break;
}
// piCout << "write" << ba.size();
//piCout << "write" << ba.size();
if (!ba.isEmpty()) write(ba);
# endif
#endif
cursor_tm.reset();
cursor_blink = true;
}
void PITerminal::write(PIKbdListener::KeyEvent ke) {
if (isSpecialKey(ke.key))
write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
if (isSpecialKey(ke.key)) write((PIKbdListener::SpecialKey)ke.key, ke.modifiers);
else {
PIByteArray ba;
# ifdef WINDOWS
#ifdef WINDOWS
ba << uchar(PIChar((ushort)ke.key).toConsole1Byte());
# else
#else
ba = PIString(PIChar((ushort)ke.key)).toUTF8();
# endif
#endif
write(ba);
}
}
PIVector<PIVector<PIScreenTypes::Cell>> PITerminal::content() {
PIVector<PIVector<PIScreenTypes::Cell> > PITerminal::content() {
readConsole();
PIVector<PIVector<PIScreenTypes::Cell>> ret = cells;
PIVector<PIVector<PIScreenTypes::Cell> > ret = cells;
if (cursor_blink && cursor_visible)
if (cursor_x >= 0 && cursor_x < size_x)
if (cursor_y >= 0 && cursor_y < size_y) ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
if (cursor_y >= 0 && cursor_y < size_y)
ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse;
return ret;
}
@@ -299,11 +295,11 @@ bool PITerminal::isSpecialKey(int k) {
void PITerminal::initPrivate() {
# ifdef WINDOWS
#ifdef WINDOWS
PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
PRIVATE->pipe = INVALID_HANDLE_VALUE;
PRIVATE->pi.hProcess = 0;
# else
#else
PRIVATE->shell = "/bin/bash";
PRIVATE->read_buf.reserve(BUFFER_SIZE);
PRIVATE->read_buf.fill(0);
@@ -315,14 +311,14 @@ void PITerminal::initPrivate() {
PRIVATE->last_read = true;
PRIVATE->esc_seq.clear();
PRIVATE->cur_format = PIScreenTypes::CellFormat();
# endif
#endif
cursor_blink = cursor_visible = true;
size_x = size_y = 0;
}
void PITerminal::readConsole() {
# ifdef WINDOWS
#ifdef WINDOWS
if (!PRIVATE->shm) return;
PITerminalAuxData data;
PRIVATE->shm->read(&data, sizeof(data));
@@ -335,20 +331,20 @@ void PITerminal::readConsole() {
ba.resize(data.cells_size);
PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data));
ba >> cells;
# endif
// piCout << cursor_x << cursor_y;
#endif
//piCout << cursor_x << cursor_y;
}
void PITerminal::getCursor(int & x, int & y) {
# ifdef WINDOWS
#ifdef WINDOWS
if (!PRIVATE->shm) return;
int sz = 0;
PRIVATE->shm->read(&sz, 4);
# else
#else
x = PRIVATE->cur_x;
y = PRIVATE->cur_y;
# endif
#endif
}
@@ -374,7 +370,7 @@ void PITerminal::run() {
cursor_tm.reset();
cursor_blink = !cursor_blink;
}
# ifndef WINDOWS
#ifndef WINDOWS
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return;
PRIVATE->tmp_buf.resize(BUFFER_SIZE);
@@ -382,8 +378,8 @@ void PITerminal::run() {
bool used = false;
if (readed > 0) {
PRIVATE->last_read = true;
// piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
// piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
//piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e");
//piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed));
PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed));
for (;;) {
int ind = -1;
@@ -399,27 +395,28 @@ void PITerminal::run() {
}
bool parse = PRIVATE->read_buf.size_s() >= BUFFER_SIZE;
if (PRIVATE->read_buf.size_s() == 1)
if (PRIVATE->read_buf[0] < 0x80) parse = true;
if (PRIVATE->read_buf[0] < 0x80)
parse = true;
if (parse) {
parseInput(PIString::fromUTF8(PRIVATE->read_buf));
parseInput(PIString(PRIVATE->read_buf));
PRIVATE->read_buf.clear();
}
// printf("%s", PRIVATE->read_buf.data());
//printf("%s", PRIVATE->read_buf.data());
}
if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) {
parseInput(PIString::fromUTF8(PRIVATE->read_buf));
parseInput(PIString(PRIVATE->read_buf));
PRIVATE->read_buf.clear();
}
PRIVATE->last_read = false;
# endif
# endif
#endif
}
# ifndef WINDOWS
#ifndef WINDOWS
void PITerminal::parseInput(const PIString & s) {
// piCoutObj << s.replaceAll("\e", "\\e");
// printf("%s", s.data());
//piCoutObj << s.replaceAll("\e", "\\e");
//printf("%s", s.data());
for (int i = 0; i < s.size_s(); ++i) {
if (s[i].unicode16Code() == 0) break;
if (PRIVATE->is_esc_seq) {
@@ -432,7 +429,7 @@ void PITerminal::parseInput(const PIString & s) {
if (isCompleteEscSeq(PRIVATE->esc_seq)) {
PRIVATE->is_esc_seq = false;
applyEscSeq(PRIVATE->esc_seq);
// piCoutObj << PRIVATE->esc_seq;
//piCoutObj << PRIVATE->esc_seq;
}
}
} else {
@@ -447,15 +444,14 @@ void PITerminal::parseInput(const PIString & s) {
}
if (s[i] == '\r') continue;
if (s[i] == '\n') {
// piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
//piCoutObj << "new line";
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format;
PRIVATE->line_format = PRIVATE->cur_format;
PRIVATE->cur_x = 0;
moveCursor(0, 1);
continue;
}
// piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y;
//piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y;
cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i];
cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format;
moveCursor(1, 0);
@@ -479,7 +475,7 @@ bool PITerminal::isCompleteEscSeq(const PIString & es) {
void PITerminal::applyEscSeq(PIString es) {
piCoutObj << es;
if (es.size_s() < 2) return;
// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format);
// PIScreenTypes::Cell line_cell = PIScreenTypes::Cell(' ', PRIVATE->line_format);
PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format);
if (es[1] == '?' && es.size_s() >= 2) {
char a = es.takeRight(1)[0].toAscii();
@@ -502,8 +498,7 @@ void PITerminal::applyEscSeq(PIString es) {
case 1047:
if (val) {
PRIVATE->cells_save = cells;
for (int i = 0; i < size_y; ++i)
cells[i].fill(def_cell);
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
} else {
cells = PRIVATE->cells_save;
}
@@ -518,7 +513,7 @@ void PITerminal::applyEscSeq(PIString es) {
return;
}
PIStringList args = es.split(";");
piForeachC(PIString & a, args) {
piForeachC (PIString & a, args) {
int av = a.toInt();
switch (av) {
case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break;
@@ -529,14 +524,8 @@ void PITerminal::applyEscSeq(PIString es) {
default: {
bool col = false, target = false;
int cid = av % 10;
if (av >= 30 && av <= 37) {
col = true;
target = false;
}
if (av >= 40 && av <= 47) {
col = true;
target = true;
}
if (av >= 30 && av <= 37) {col = true; target = false;}
if (av >= 40 && av <= 47) {col = true; target = true;}
if (col) {
int cfl = 0;
switch (cid) {
@@ -590,36 +579,32 @@ void PITerminal::applyEscSeq(PIString es) {
int x(0), y(0);
if (!args[0].isEmpty()) y = args[0].toInt() - 1;
if (!args[1].isEmpty()) x = args[1].toInt() - 1;
// piCoutObj << x << y;
//piCoutObj << x << y;
PRIVATE->cur_x = piClamp(x, 0, size_x - 1);
PRIVATE->cur_y = piClamp(y, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'A') { // cursor up
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'B') { // cursor down
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'D') { // cursor back
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
@@ -631,92 +616,66 @@ void PITerminal::applyEscSeq(PIString es) {
}
if (es.back() == 'd') { // goto line
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'E' || es.back() == 'e') { // next line
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'F') { // previous line
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
int v = es.toInt(); if (v == 0) v = 1;
PRIVATE->cur_x = 0;
PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1);
PRIVATE->line_format = PRIVATE->cur_format;
}
if (es.back() == 'L') { // insert lines
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1);
i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1);
--i)
cells[i] = cells[i - v];
for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1);
++j)
for (int i = 0; i < PRIVATE->cur_x; ++i)
cells[j][i] = def_cell;
int v = es.toInt(); if (v == 0) v = 1;
for (int i = piClamp(size_y - 1, PRIVATE->win_y0, PRIVATE->win_y1); i >= piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); --i) cells[i] = cells[i - v];
for (int j = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(PRIVATE->cur_y + v, PRIVATE->win_y0, PRIVATE->win_y1); ++j)
for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
}
if (es.back() == 'M') { // delete lines
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1);
i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1);
++i)
cells[i] = cells[i + v];
int v = es.toInt(); if (v == 0) v = 1;
for (int i = piClamp(PRIVATE->cur_y, PRIVATE->win_y0, PRIVATE->win_y1); i < piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); ++i) cells[i] = cells[i + v];
for (int j = piClamp(size_y - v, PRIVATE->win_y0, PRIVATE->win_y1); j < piClamp(size_y, PRIVATE->win_y0, PRIVATE->win_y1); ++j)
for (int i = 0; i < PRIVATE->cur_x; ++i)
cells[j][i] = def_cell;
for (int i = 0; i < PRIVATE->cur_x; ++i) cells[j][i] = def_cell;
}
if (es.back() == 'P') { // delete characters
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
for (int i = PRIVATE->cur_x; i < size_x - v; ++i)
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v];
for (int i = size_x - v; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
int v = es.toInt(); if (v == 0) v = 1;
for (int i = PRIVATE->cur_x; i < size_x - v; ++i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v];
for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
}
if (es.back() == '@') { // delete characters
es.cutLeft(1).cutRight(1);
int v = es.toInt();
if (v == 0) v = 1;
for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i)
cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v];
for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
int v = es.toInt(); if (v == 0) v = 1;
for (int i = size_x - 1; i >= PRIVATE->cur_x + v; --i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i - v];
for (int i = PRIVATE->cur_x; i < PRIVATE->cur_x + v; ++i) cells[PRIVATE->cur_y][i] = def_cell;
}
if (es.back() == 'J') { // erase data
es.cutLeft(1).cutRight(1);
int v = es.toInt();
switch (v) {
case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i)
cells[i].fill(def_cell);
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell);
break;
case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = 0; i < PRIVATE->cur_y; ++i)
cells[i].fill(def_cell);
for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
for (int i = 0; i < PRIVATE->cur_y; ++i) cells[i].fill(def_cell);
break;
case 2:
for (int i = 0; i < size_y; ++i)
cells[i].fill(def_cell);
// PRIVATE->cur_x = PRIVATE->cur_y = 0;
for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell);
//PRIVATE->cur_x = PRIVATE->cur_y = 0;
break;
}
}
@@ -725,14 +684,14 @@ void PITerminal::applyEscSeq(PIString es) {
int v = es.toInt();
switch (v) {
case 0:
for (int i = PRIVATE->cur_x; i < size_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
break;
case 1:
for (int i = 0; i <= PRIVATE->cur_x; ++i)
cells[PRIVATE->cur_y][i] = def_cell;
for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell;
break;
case 2:
cells[PRIVATE->cur_y].fill(def_cell);
break;
case 2: cells[PRIVATE->cur_y].fill(def_cell); break;
}
}
}
@@ -751,7 +710,7 @@ void PITerminal::moveCursor(int dx, int dy) {
}
if (PRIVATE->cur_y >= size_y) {
int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1);
// piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
//piCout << "scroll" << size_x << size_y << size_y - scroll - 1;
PRIVATE->cur_y = size_y - 1;
for (int y = 0; y < size_y - scroll; ++y)
cells[y] = cells[y + scroll];
@@ -762,18 +721,16 @@ void PITerminal::moveCursor(int dx, int dy) {
int PITerminal::termType(const PIString & t) {
if (t == "xterm")
return PIKbdListener::vt_xterm;
else if (t == "linux")
return PIKbdListener::vt_linux;
if (t == "xterm") return PIKbdListener::vt_xterm;
else if (t == "linux") return PIKbdListener::vt_linux;
return PIKbdListener::vt_none;
}
# endif
#endif
bool PITerminal::initialize() {
destroy();
# ifdef WINDOWS
#ifdef WINDOWS
/*SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = true;
@@ -789,18 +746,18 @@ bool PITerminal::initialize() {
destroy();
return false;
}*/
// CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
// SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
// SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
// GetStartupInfoA(&PRIVATE->si);
//CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
//SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
//SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
//GetStartupInfoA(&PRIVATE->si);
memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
PRIVATE->si.cb = sizeof(STARTUPINFO);
// PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
//PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS;
// PRIVATE->si.hStdInput = PRIVATE->pipe;
// PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
// PRIVATE->si.hStdError = PRIVATE->hConBuf;
//PRIVATE->si.hStdInput = PRIVATE->pipe;
//PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
//PRIVATE->si.hStdError = PRIVATE->hConBuf;
PRIVATE->si.wShowWindow = SW_HIDE;
PRIVATE->si.dwXCountChars = 80;
PRIVATE->si.dwYCountChars = 24;
@@ -810,28 +767,12 @@ bool PITerminal::initialize() {
PIString shmh = PIString::fromNumber(randomi() % 10000);
PIString pname = "\\\\.\\pipe\\piterm" + shmh;
PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
if (!CreateProcessA(0,
(LPSTR)cmd.dataAscii(),
0,
0,
false,
CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
0,
0,
&PRIVATE->si,
&PRIVATE->pi)) {
if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) {
piCoutObj << "CreateProcess error," << errorString();
destroy();
return false;
}
PRIVATE->pipe = CreateNamedPipeA((LPSTR)pname.dataAscii(),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
2,
PIPE_BUFFER_SIZE,
PIPE_BUFFER_SIZE,
1000,
NULL);
PRIVATE->pipe = CreateNamedPipe((LPSTR)pname.dataAscii(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 1000, NULL);
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) {
piCoutObj << "CreateNamedPipe error," << errorString();
destroy();
@@ -851,27 +792,26 @@ bool PITerminal::initialize() {
return false;
}
if (PRIVATE->shm) delete PRIVATE->shm;
PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024 * 1024);
PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024*1024);
CloseHandle(PRIVATE->pi.hThread);
resize(dsize_x, dsize_y);
# else
#else
# ifdef HAS_FORKPTY
char pty[256];
memset(pty, 0, 256);
char pty[256]; memset(pty, 0, 256);
winsize ws;
ws.ws_col = dsize_x;
ws.ws_row = dsize_y;
PIStringList env = PIProcess::currentEnvironment();
piForeachC(PIString & e, env)
piForeachC (PIString & e, env)
if (e.startsWith("TERM=")) {
PRIVATE->term_type = termType(e.mid(5).trim().toLowerCase());
// piCout << PRIVATE->term_type;
//piCout << PRIVATE->term_type;
break;
}
pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws);
// piCoutObj << fr << PRIVATE->fd << pty;
//piCoutObj << fr << PRIVATE->fd << pty;
if (fr == 0) {
char ** argv = new char *[2];
char ** argv = new char*[2];
PIByteArray shell = PRIVATE->shell.toByteArray();
argv[0] = new char[shell.size() + 1];
memcpy(argv[0], shell.data(), shell.size());
@@ -913,34 +853,36 @@ bool PITerminal::initialize() {
resize(size_x, size_y);
}
# endif
# endif
#endif
cursor_blink = false;
cursor_tm.reset();
start(25_Hz);
start(40);
return true;
}
void PITerminal::destroy() {
// piCout << "destroy ...";
//piCout << "destroy ...";
stop();
waitForFinish(1_s);
# ifdef WINDOWS
waitForFinish(1000);
#ifdef WINDOWS
if (PRIVATE->pi.hProcess) {
// piCout << "term";
// TerminateProcess(PRIVATE->pi.hProcess, 0);
//piCout << "term";
//TerminateProcess(PRIVATE->pi.hProcess, 0);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId);
CloseHandle(PRIVATE->pi.hProcess);
}
if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe);
if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf);
// piCout << "destroy" << size_y;
# else
//piCout << "destroy" << size_y;
#else
# ifdef HAS_FORKPTY
if (PRIVATE->pid != 0) kill(PRIVATE->pid, SIGKILL);
if (PRIVATE->fd != 0) ::close(PRIVATE->fd);
# endif
if (PRIVATE->pid != 0)
kill(PRIVATE->pid, SIGKILL);
if (PRIVATE->fd != 0)
::close(PRIVATE->fd);
# endif
#endif
initPrivate();
}
@@ -949,17 +891,17 @@ bool PITerminal::resize(int cols, int rows) {
bool ret = true;
dsize_x = cols;
dsize_y = rows;
# ifdef WINDOWS
#ifdef WINDOWS
if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false;
PIByteArray msg;
msg << int(mtResize) << dsize_x << dsize_y;
writePipe(PRIVATE->pipe, msg);
# else
#else
# ifdef HAS_FORKPTY
if (PRIVATE->fd == 0) return false;
size_x = dsize_x;
size_y = dsize_y;
// piCout << "resize" << PRIVATE->fd << size_x << size_y;
//piCout << "resize" << PRIVATE->fd << size_x << size_y;
winsize ws;
ws.ws_col = cols;
ws.ws_row = rows;
@@ -970,7 +912,7 @@ bool PITerminal::resize(int cols, int rows) {
for (int i = 0; i < size_y; ++i)
PRIVATE->cells_save[i].resize(size_x);
# endif
# endif
#endif
cells.resize(size_y);
for (int i = 0; i < size_y; ++i)
cells[i].resize(size_x);

View File

@@ -20,7 +20,7 @@
#include "piauth.h"
#define PIAUTH_NOISE_MAX_SIZE 256
PIAuth::PIAuth(const PIByteArray & sign): PIObject() {
PIAuth::PIAuth(const PIByteArray & sign) : PIObject() {
setName("Client");
role = Client;
state = NotConnected;
@@ -56,7 +56,7 @@ PIByteArray PIAuth::startServer() {
state = AuthProbe;
PIByteArray ba;
crypt.generateKeypair(my_pk, box_sk);
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE + 128);
PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE+128);
ba << (int)state << custom_info << sign_pk << my_pk << noise;
PIByteArray sign = crypt.signMessage(ba, sign_sk);
ba << sign;
@@ -70,12 +70,12 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
int s;
ba >> s;
rstate = (State)s;
// if (state != rstate) return disconect(ba);
// if (state != rstate) return disconect(ba);
// client side
//client side
if (role == Client) {
if (state == AuthProbe && rstate == AuthProbe) {
if (ba.size() < sizeof(int) * 5) return disconnect(ba, "invalid data size");
if (ba.size() < sizeof(int)*5) return disconnect(ba, "invalid data size");
PIByteArray rinfo;
PIByteArray rsign;
PIByteArray rsign_pk;
@@ -103,7 +103,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
tba << sign;
tba = crypt.crypt(tba, box_pk, box_sk);
state = AuthReply;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << tba << my_pk << noise;
sign = crypt.signMessage(ba, sign_sk);
ba << sign;
@@ -154,14 +154,14 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
if (state == Connected && rstate == Connected) {
ba.clear();
state = Connected;
connected(PIString());
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
ba << (int)state << crypt.crypt(custom_info, secret_key) << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
@@ -169,7 +169,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
// server side
if (role == Server) {
if (state == AuthProbe && rstate == AuthReply) {
if (ba.size() < sizeof(int) * 4) return disconnect(ba, "invalid data size");
if (ba.size() < sizeof(int)*4) return disconnect(ba, "invalid data size");
PIByteArray ctba, tba;
PIByteArray noise;
PIByteArray rsign1, rsign2;
@@ -179,7 +179,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
bool ok = false;
tba = crypt.decrypt(ctba, pk, box_sk, &ok);
if (tba.isEmpty() || !ok) return disconnect(ba, "Message corrupted");
if (tba.size() < sizeof(int) * 3) return disconnect(tba, "invalid data size");
if (tba.size() < sizeof(int)*3) return disconnect(tba, "invalid data size");
tba >> rsign_pk >> box_pk >> mpk >> rsign2;
if (pk != box_pk || mpk != my_pk) return disconnect(ba, "Invalid public key");
ba.clear();
@@ -197,7 +197,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
ba.clear();
tba.clear();
state = PassRequest;
noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << sign_pk << noise << box_pk;
tba = crypt.crypt(tba, box_pk, box_sk);
ba << (int)state << tba;
@@ -223,7 +223,7 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
if (ctba.isEmpty() || pass_hash.isEmpty()) auth = false;
passwordCheck(auth);
if (!auth) {
// piSleep(1);
// piSleep(1);
return disconnect(ba, "Invalid password");
}
state = KeyExchange;
@@ -238,8 +238,8 @@ PIAuth::State PIAuth::receive(PIByteArray & ba) {
rinfo = crypt.decrypt(rinfo, secret_key, &ok);
if (!ok) return disconnect(ba, "Error while exchange keys");
state = Connected;
connected(PIString::fromUTF8(rinfo));
ba << (int)state << crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
connected(rinfo);
ba << (int)state << crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
return state;
}
}
@@ -276,7 +276,7 @@ PIAuth::State PIAuth::disconnect(PIByteArray & ba, const PIString & error) {
bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
for (int i = 0; i < auth_pkeys.size_s(); ++i) {
for (int i=0; i<auth_pkeys.size_s(); ++i) {
if (pkey == auth_pkeys[i]) return true;
}
return false;
@@ -286,7 +286,7 @@ bool PIAuth::isAuthorizedKey(const PIByteArray & pkey) {
PIByteArray PIAuth::createSKMessage() {
secret_key = crypt.generateKey();
PIByteArray tba;
PIByteArray noise = crypt.generateRandomBuff(randomi() % PIAUTH_NOISE_MAX_SIZE);
PIByteArray noise = crypt.generateRandomBuff(randomi()%PIAUTH_NOISE_MAX_SIZE);
tba << secret_key << noise;
tba = crypt.crypt(tba, box_pk, box_sk);
PIByteArray ret;

View File

@@ -22,9 +22,7 @@
# include <sodium.h>
#endif
#define PICRYPT_DISABLED_WARNING \
piCout << "[PICrypt]" \
<< "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
#define PICRYPT_DISABLED_WARNING piCout << "[PICrypt]" << "Warning: PICrypt is disabled, to enable install sodium library and rebuild pip";
const char hash_def_key[] = "_picrypt_\0\0\0\0\0\0\0";
const int hash_def_key_size = 9;
@@ -32,9 +30,7 @@ const int hash_def_key_size = 9;
PICrypt::PICrypt() {
#ifdef PIP_CRYPT
if (!init())
piCout << "[PICrypt]"
<< "Error while initialize sodium!";
if (!init()) piCout << "[PICrypt]" << "Error while initialize sodium!";
nonce_.resize(crypto_secretbox_NONCEBYTES);
key_.resize(crypto_secretbox_KEYBYTES);
randombytes_buf(key_.data(), key_.size());
@@ -57,7 +53,7 @@ PIByteArray PICrypt::setKey(const PIString & secret) {
#ifdef PIP_CRYPT
hash.resize(crypto_generichash_BYTES);
PIByteArray s(secret.data(), secret.size());
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar *)hash_def_key, hash_def_key_size);
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar*)hash_def_key, hash_def_key_size);
hash.resize(key_.size());
setKey(hash);
#endif
@@ -80,8 +76,9 @@ PIByteArray PICrypt::crypt(const PIByteArray & data) {
PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' ');
// return PIByteArray();
if (key.size() != crypto_secretbox_KEYBYTES)
key.resize(crypto_secretbox_KEYBYTES, ' ');
//return PIByteArray();
if (!init()) return ret;
PIByteArray n;
ret.resize(data.size() + crypto_secretbox_MACBYTES);
@@ -96,7 +93,7 @@ PIByteArray PICrypt::crypt(const PIByteArray & data, PIByteArray key) {
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) {
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool *ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (crypt_data.size() < nonce_.size() + crypto_secretbox_MACBYTES) {
@@ -116,13 +113,14 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, bool * ok) {
}
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool * ok) {
PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bool *ok) {
PIByteArray ret;
#ifdef PIP_CRYPT
if (key.size() != crypto_secretbox_KEYBYTES) key.resize(crypto_secretbox_KEYBYTES, ' ');
if (key.size() != crypto_secretbox_KEYBYTES)
key.resize(crypto_secretbox_KEYBYTES, ' ');
/*if (ok) *ok = false;
return PIByteArray();
}*/
}*/
if (crypt_data.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES) {
if (ok) *ok = false;
return PIByteArray();
@@ -136,8 +134,7 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, PIByteArray key, bo
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok)
*ok = true;
} else if (ok) *ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
@@ -151,7 +148,7 @@ PIByteArray PICrypt::hash(const PIString & secret) {
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
PIByteArray s(secret.data(), secret.size());
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(), (const uchar *)hash_def_key, hash_def_key_size);
crypto_generichash(hash.data(), hash.size(), s.data(), s.size(),(const uchar*)hash_def_key, hash_def_key_size);
#else
PICRYPT_DISABLED_WARNING
#endif
@@ -164,7 +161,7 @@ PIByteArray PICrypt::hash(const PIByteArray & data) {
#ifdef PIP_CRYPT
if (!init()) return hash;
hash.resize(crypto_generichash_BYTES);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), (const uchar *)hash_def_key, hash_def_key_size);
crypto_generichash(hash.data(), hash.size(), data.data(), data.size(), (const uchar*)hash_def_key, hash_def_key_size);
#else
PICRYPT_DISABLED_WARNING
#endif
@@ -172,7 +169,7 @@ PIByteArray PICrypt::hash(const PIByteArray & data) {
}
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char * key, size_t keylen) {
PIByteArray PICrypt::hash(const PIByteArray & data, const unsigned char *key, size_t keylen) {
PIByteArray hash;
#ifdef PIP_CRYPT
if (!init()) return hash;
@@ -195,16 +192,13 @@ size_t PICrypt::sizeHash() {
}
ullong PICrypt::shorthash(const PIString & s, PIByteArray key) {
ullong PICrypt::shorthash(const PIString& s, PIByteArray key) {
ullong hash = 0;
#ifdef PIP_CRYPT
if (crypto_shorthash_BYTES != sizeof(hash))
piCout << "[PICrypt]"
<< "internal error: bad hash size";
if (crypto_shorthash_BYTES != sizeof(hash)) piCout << "[PICrypt]" << "internal error: bad hash size";
if (!init()) return hash;
if (key.size() != crypto_shorthash_KEYBYTES) {
piCout << "[PICrypt]"
<< "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
piCout << "[PICrypt]" << "invalid key size" << key.size() << ", shoud be" << crypto_shorthash_KEYBYTES << ", filled zeros";
key.resize(crypto_shorthash_KEYBYTES, 0);
}
PIByteArray in(s.data(), s.size());
@@ -351,13 +345,16 @@ PIByteArray PICrypt::crypt(const PIByteArray & data, const PIByteArray & public_
PIByteArray ret;
#ifdef PIP_CRYPT
if (!init()) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES) return ret;
if (secret_key.size() != crypto_box_SECRETKEYBYTES) return ret;
if (public_key.size() != crypto_box_PUBLICKEYBYTES)
return ret;
if (secret_key.size() != crypto_box_SECRETKEYBYTES)
return ret;
PIByteArray n;
ret.resize(data.size() + crypto_box_MACBYTES);
n.resize(crypto_box_NONCEBYTES);
randombytes_buf(n.data(), n.size());
if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0) return PIByteArray();
if (crypto_box_easy(ret.data(), data.data(), data.size(), n.data(), public_key.data(), secret_key.data()) != 0)
return PIByteArray();
ret.append(n);
#else
PICRYPT_DISABLED_WARNING
@@ -386,13 +383,11 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray &
n.resize(crypto_secretbox_NONCEBYTES);
ret.resize(crypt_data.size() - n.size() - crypto_secretbox_MACBYTES);
memcpy(n.data(), crypt_data.data(crypt_data.size() - n.size()), n.size());
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) !=
0) {
if (crypto_box_open_easy(ret.data(), crypt_data.data(), crypt_data.size() - n.size(), n.data(), public_key.data(), secret_key.data()) != 0) {
if (ok) *ok = false;
// piCout << "[PICrypt]" << "bad key_";
return PIByteArray();
} else if (ok)
*ok = true;
} else if (ok) *ok = true;
#else
PICRYPT_DISABLED_WARNING
#endif
@@ -402,24 +397,16 @@ PIByteArray PICrypt::decrypt(const PIByteArray & crypt_data, const PIByteArray &
PIByteArray PICrypt::passwordHash(const PIString & password, const PIByteArray & seed) {
#ifdef crypto_pwhash_ALG_ARGON2I13
// char out[crypto_pwhash_STRBYTES];
// char out[crypto_pwhash_STRBYTES];
PIByteArray pass = password.toUTF8();
PIByteArray n = hash(seed);
PIByteArray ph;
ph.resize(crypto_box_SEEDBYTES);
n.resize(crypto_pwhash_SALTBYTES);
// randombytes_buf(n.data(), n.size());
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data());
int r = crypto_pwhash(ph.data(),
ph.size(),
(const char *)pass.data(),
pass.size(),
n.data(),
crypto_pwhash_argon2i_opslimit_moderate(),
crypto_pwhash_argon2i_memlimit_moderate(),
crypto_pwhash_ALG_ARGON2I13);
// crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(),
// crypto_pwhash_argon2i_memlimit_moderate());
// randombytes_buf(n.data(), n.size());
// crypto_shorthash(n.data(), seed.data(), seed.size(), PIByteArray(crypto_shorthash_KEYBYTES).data());
int r = crypto_pwhash(ph.data(), ph.size(), (const char*)pass.data(), pass.size(), n.data(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate(), crypto_pwhash_ALG_ARGON2I13);
//crypto_pwhash_str(out, (const char*)pass.data(), pass.size(), crypto_pwhash_argon2i_opslimit_moderate(), crypto_pwhash_argon2i_memlimit_moderate());
pass.fill(0);
if (r != 0) return PIByteArray();
return ph;
@@ -445,13 +432,17 @@ bool PICrypt::init() {
#ifdef PIP_CRYPT
static bool inited = false;
if (inited) return true;
// piCout << "[PICrypt]" << "init ...";
//piCout << "[PICrypt]" << "init ...";
inited = sodium_init();
if (!inited) inited = sodium_init();
// piCout << "[PICrypt]" << "init" << inited;
if (!inited)
inited = sodium_init();
//piCout << "[PICrypt]" << "init" << inited;
return inited;
#else
PICRYPT_DISABLED_WARNING
#endif
return false;
}

View File

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

View File

@@ -1,6 +1,6 @@
/*! \file pifft_p.h
* \brief Class for FFT, IFFT and Hilbert transformations
*/
*/
/*
PIP - Platform Independent Primitives
Private header for fftw3
@@ -23,8 +23,8 @@
#ifndef PIFFT_P_H
#define PIFFT_P_H
#include "picout.h"
#include "pivector.h"
#include "picout.h"
#if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq)
# include "fftw3.h"
#else
@@ -35,42 +35,43 @@
#endif
template<typename T>
class PIFFTW_Private {
template <typename T>
class PIFFTW_Private
{
public:
explicit PIFFTW_Private() {
plan = 0;
// #ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
// #endif
//#ifndef PIP_FFTW
// piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1";
//#endif
p_makeThreadSafe();
}
~PIFFTW_Private() { p_destroyPlan(plan); }
~PIFFTW_Private() {p_destroyPlan(plan);}
const PIVector<complex<T>> & calcFFT(const PIVector<complex<T>> & in) {
const PIVector<complex<T> > & calcFFT(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_complex)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_complex);
}
p_executePlan_c2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T>> & calcFFT(const PIVector<T> & in) {
const PIVector<complex<T> > & calcFFT(const PIVector<T> & in) {
if (prepare != PlanParams(in.size(), fo_real)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_real);
}
p_executePlan_r2c(plan, in.data(), p_out.data());
return p_out;
}
const PIVector<complex<T>> & calcFFTinverse(const PIVector<complex<T>> & in) {
const PIVector<complex<T> > & calcFFTinverse(const PIVector<complex<T> > & in) {
if (prepare != PlanParams(in.size(), fo_inverse)) {
p_out.resize(in.size());
// piCout << "[PIFFTW]" << "creating plan";
piCout << "[PIFFTW]" << "creating plan";
p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED);
prepare = PlanParams(in.size(), fo_inverse);
}
@@ -78,11 +79,7 @@ public:
return p_out;
}
enum FFT_Operation {
fo_real,
fo_complex,
fo_inverse
};
enum FFT_Operation {fo_real, fo_complex, fo_inverse};
void preparePlan(int size, int op) {
p_inr.clear();
@@ -104,7 +101,9 @@ public:
p_out.resize(size);
p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED);
break;
default: size = 0; break;
default:
size = 0;
break;
}
prepare = PlanParams(size, (FFT_Operation)op);
}
@@ -118,128 +117,62 @@ public:
inline void p_makeThreadSafe() {}
struct PlanParams {
PlanParams() {
size = 0;
op = fo_complex;
}
PlanParams(int size_, FFT_Operation op_) {
size = size_;
op = op_;
}
bool isValid() { return size > 0; }
bool operator==(const PlanParams & v) const { return (v.size == size) && (v.op == op); }
bool operator!=(const PlanParams & v) const { return !(*this == v); }
PlanParams() {size = 0; op = fo_complex;}
PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;}
bool isValid() {return size > 0;}
bool operator ==(const PlanParams & v) const {return (v.size == size) && (v.op == op);}
bool operator !=(const PlanParams & v) const {return !(*this == v);}
int size;
FFT_Operation op;
};
PIVector<complex<T>> p_in;
PIVector<complex<T> > p_in;
PIVector<T> p_inr;
PIVector<complex<T>> p_out;
PIVector<complex<T> > p_out;
void * plan;
PlanParams prepare;
};
#ifdef PIP_FFTWf
template<>
inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags);
}
template<>
inline void PIFFTW_Private<float>::p_executePlan(void * plan) {
fftwf_execute((fftwf_plan)plan);
}
template<>
inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out);
}
template<>
inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);
}
template<>
inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {
if (plan) fftwf_destroy_plan((fftwf_plan)plan);
plan = 0;
}
template<> inline void PIFFTW_Private<float>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);}
template<> inline void PIFFTW_Private<float>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags);}
template<> inline void PIFFTW_Private<float>::p_executePlan(void * plan) {fftwf_execute((fftwf_plan)plan);}
template<> inline void PIFFTW_Private<float>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out);}
template<> inline void PIFFTW_Private<float>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);}
template<> inline void PIFFTW_Private<float>::p_destroyPlan(void *& plan) {if (plan) fftwf_destroy_plan((fftwf_plan)plan); plan = 0;}
# ifdef PIP_FFTWf_THREADSAFE
template<>
inline void PIFFTW_Private<float>::p_makeThreadSafe() {
fftwf_make_planner_thread_safe();
}
template<> inline void PIFFTW_Private<float>::p_makeThreadSafe() {fftwf_make_planner_thread_safe();}
# endif
#endif // PIP_FFTWf
#ifdef PIP_FFTW
template<>
inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan(void * plan) {
fftw_execute((fftw_plan)plan);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);
}
template<>
inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {
if (plan) fftw_destroy_plan((fftw_plan)plan);
plan = 0;
}
template<> inline void PIFFTW_Private<double>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);}
template<> inline void PIFFTW_Private<double>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);}
template<> inline void PIFFTW_Private<double>::p_executePlan(void * plan) {fftw_execute((fftw_plan)plan);}
template<> inline void PIFFTW_Private<double>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);}
template<> inline void PIFFTW_Private<double>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);}
template<> inline void PIFFTW_Private<double>::p_destroyPlan(void *& plan) {if (plan) fftw_destroy_plan((fftw_plan)plan); plan = 0;}
# ifdef PIP_FFTW_THREADSAFE
template<>
inline void PIFFTW_Private<double>::p_makeThreadSafe() {
fftw_make_planner_thread_safe();
}
template<> inline void PIFFTW_Private<double>::p_makeThreadSafe() {fftw_make_planner_thread_safe();}
# endif
#endif // PIP_FFTW
#ifdef PIP_FFTWl
template<>
inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);
}
template<>
inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {
fftwl_execute((fftwl_plan)plan);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {
fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {
fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);
}
template<>
inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {
if (plan) fftwl_destroy_plan((fftwl_plan)plan);
plan = 0;
}
template<> inline void PIFFTW_Private<ldouble>::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {
plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);}
template<> inline void PIFFTW_Private<ldouble>::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {
plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);}
template<> inline void PIFFTW_Private<ldouble>::p_executePlan(void * plan) {fftwl_execute((fftwl_plan)plan);}
template<> inline void PIFFTW_Private<ldouble>::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);}
template<> inline void PIFFTW_Private<ldouble>::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);}
template<> inline void PIFFTW_Private<ldouble>::p_destroyPlan(void *& plan) {if (plan) fftwl_destroy_plan((fftwl_plan)plan); plan = 0;}
# ifdef PIP_FFTWl_THREADSAFE
template<>
inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {
fftwl_make_planner_thread_safe();
}
template<> inline void PIFFTW_Private<ldouble>::p_makeThreadSafe() {fftwl_make_planner_thread_safe();}
# endif
#endif // PIP_FFTWl

View File

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

View File

@@ -43,7 +43,7 @@
* You can use this class as base for your own classes. Use \a cryptData()
* and \a decryptData() when send and receive your data.
*
*/
*/
PIEthUtilBase::PIEthUtilBase() {
@@ -51,7 +51,8 @@ PIEthUtilBase::PIEthUtilBase() {
}
PIEthUtilBase::~PIEthUtilBase() {}
PIEthUtilBase::~PIEthUtilBase() {
}
void PIEthUtilBase::setCryptEnabled(bool on) {

View File

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

View File

@@ -22,9 +22,7 @@
# pragma GCC diagnostic ignored "-Wnonnull"
#endif
#include "pistreampacker.h"
#include "piiodevice.h"
#include "piliterals_bytes.h"
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
@@ -45,7 +43,7 @@
*
* Use \a assignDevice() to connect device to this %PIStreamPacker.
*
*/
*/
PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
@@ -53,7 +51,7 @@ PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
aggressive_optimization = true;
packet_size = -1;
size_crypted_size = sizeof(int);
crypt_frag_size = 1_MiB;
crypt_frag_size = 1024*1024;
max_packet_size = 1400;
packet_sign = 0xAFBE;
assignDevice(dev);
@@ -63,8 +61,7 @@ PIStreamPacker::PIStreamPacker(PIIODevice * dev): PIObject() {
void PIStreamPacker::setCryptSizeEnabled(bool on) {
crypt_size = on;
if (crypt_size) {
PIByteArray ba;
ba << int(0);
PIByteArray ba; ba << int(0);
size_crypted_size = cryptData(ba).size_s();
} else
size_crypted_size = sizeof(int);
@@ -83,51 +80,45 @@ void PIStreamPacker::send(const PIByteArray & data) {
PIByteArray cd;
if (crypt_frag) {
int fcnt = (data.size_s() - 1) / crypt_frag_size + 1, fst = 0;
// piCout << "crypt_frag send" << fcnt << "frags";
//piCout << "crypt_frag send" << fcnt << "frags";
PIByteArray frag;
for (int i = 0; i < fcnt; ++i) {
if (i == fcnt - 1)
frag = PIByteArray(data.data(fst), data.size_s() - fst);
else
frag = PIByteArray(data.data(fst), crypt_frag_size);
if (i == fcnt - 1) frag = PIByteArray(data.data(fst), data.size_s() - fst);
else frag = PIByteArray(data.data(fst), crypt_frag_size);
fst += crypt_frag_size;
cd << cryptData(frag);
}
} else {
cd = cryptData(data);
}
// piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
//piCout << "crypt" << data.size() << "->" << cd.size() << key().size();
PIByteArray hdr, part;
hdr << packet_sign;
if (crypt_size) {
PIByteArray crsz;
crsz << int(cd.size_s());
PIByteArray crsz; crsz << int(cd.size_s());
hdr.append(cryptData(crsz));
} else
hdr << int(cd.size_s());
cd.insert(0, hdr);
int pcnt = (cd.size_s() - 1) / max_packet_size + 1, pst = 0;
for (int i = 0; i < pcnt; ++i) {
if (i == pcnt - 1)
part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else
part = PIByteArray(cd.data(pst), max_packet_size);
// piCout << "send" << part.size();
if (i == pcnt - 1) part = PIByteArray(cd.data(pst), cd.size_s() - pst);
else part = PIByteArray(cd.data(pst), max_packet_size);
//piCout << "send" << part.size();
sendRequest(part);
pst += max_packet_size;
}
}
void PIStreamPacker::received(const uchar * readed, ssize_t size) {
if (size <= 0) return;
void PIStreamPacker::received(uchar * readed, int size) {
received(PIByteArray(readed, size));
}
void PIStreamPacker::received(const PIByteArray & data) {
stream.append(data);
// piCout << "rec" << data.size();
//piCout << "rec" << data.size();
while (!stream.isEmpty()) {
int hdr_size = sizeof(packet_sign) + size_crypted_size;
if (packet_size < 0) {
@@ -135,10 +126,8 @@ void PIStreamPacker::received(const PIByteArray & data) {
ushort sign(0);
memcpy(&sign, stream.data(), 2);
if (sign != packet_sign) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
int sz = -1;
@@ -147,10 +136,8 @@ void PIStreamPacker::received(const PIByteArray & data) {
memcpy(crsz.data(), stream.data(2), size_crypted_size);
crsz = decryptData(crsz);
if (crsz.size() < sizeof(sz)) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
crsz >> sz;
@@ -158,10 +145,8 @@ void PIStreamPacker::received(const PIByteArray & data) {
memcpy(&sz, stream.data(2), size_crypted_size);
}
if (sz < 0) {
if (aggressive_optimization)
stream.clear();
else
stream.pop_front();
if (aggressive_optimization) stream.clear();
else stream.pop_front();
continue;
}
stream.remove(0, hdr_size);
@@ -169,8 +154,6 @@ void PIStreamPacker::received(const PIByteArray & data) {
packet_size = sz;
if (packet_size == 0)
packet_size = -1;
else
startPacketReceive(packet_size);
continue;
} else {
int ps = piMini(stream.size_s(), packet_size - packet.size_s());
@@ -179,27 +162,26 @@ void PIStreamPacker::received(const PIByteArray & data) {
if (packet.size_s() == packet_size) {
PIByteArray cd;
if (crypt_frag) {
// piCout << "decrypt frags ..." << packet_size;
//piCout << "decrypt frags ..." << packet_size;
while (packet.size_s() >= 4) {
// piCout << "decrypt frags take data ...";
//piCout << "decrypt frags take data ...";
PIByteArray frag;
// piCout << "decrypt frags take data done" << frag.size_s();
//piCout << "decrypt frags take data done" << frag.size_s();
packet >> frag;
if (frag.isEmpty()) {
// piCout << "decrypt frags corrupt, break";
//piCout << "decrypt frags corrupt, break";
cd.clear();
break;
}
cd.append(decryptData(frag));
// piCout << "decrypt frags add" << frag.size_s();
//piCout << "decrypt frags add" << frag.size_s();
}
// piCout << "decrypt frags done" << cd.size();
//piCout << "decrypt frags done" << cd.size();
} else {
cd = decryptData(packet);
}
// piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
//piCout << "decrypt" << packet.size() << "->" << cd.size() << key().size();
if (!cd.isEmpty()) {
endPacketReceive();
packetReceived(cd);
packetReceiveEvent(cd);
}
@@ -213,9 +195,8 @@ void PIStreamPacker::received(const PIByteArray & data) {
void PIStreamPacker::assignDevice(PIIODevice * dev) {
if (!dev) return;
if (!dev->infoFlags()[PIIODevice::Reliable]) {
if (!dev->infoFlags()[PIIODevice::Reliable])
piCoutObj << "Warning! Not recommended to use with non-reliable" << dev;
}
CONNECT2(void, const uchar *, ssize_t, dev, threadedReadEvent, this, received);
CONNECT1(void, PIByteArray, this, sendRequest, dev, write);
CONNECTU(dev, threadedReadEvent, this, received);
CONNECTU(this, sendRequest, dev, write);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,229 +0,0 @@
/*
PIP - Platform Independent Primitives
High-level log
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pilog.h"
#include "pidir.h"
#include "piliterals_string.h"
#include "piliterals_time.h"
#include "pitime.h"
//! \class PILog pilog.h
//! \details
//! \~english \section PILog_sec0 Synopsis
//! \~russian \section PILog_sec0 Краткий обзор
//! \~english
//! This class provide handy parsing of command-line arguments. First you should add
//! arguments to %PICLI with function \a addArgument(). Then you can check if there
//! is some argument in application command-line with function \a hasArgument(),
//! or obtain argument value by \a argumentValue().
//!
//! \~russian
//! Этот класс предоставляет удобный механизм для разбора аргументов командной строки.
//! Сперва необходимо добавить аргументы в %PICLI с помощью методов \a addArgument().
//! Далее можно проверять аргументы на наличие в командной строке методом \a hasArgument(),
//! а также получать их значения при помощи \a argumentValue().
//!
//! \~english \section PICLI_sec1 Example
//! \~russian \section PICLI_sec1 Пример
//! \~\code
//! int main(int argc, char ** argv) {
//! PICLI cli(argc, argv);
//! cli.addArgument("console");
//! cli.addArgument("debug");
//! cli.addArgument("Value", "v", "value", true);
//! if (cli.hasArgument("console"))
//! piCout << "console active";
//! if (cli.hasArgument("debug"))
//! piCout << "debug active";
//! piCout << "Value =" << cli.argumentValue("Value");
//! return 0;
//! }
//! \endcode
//!
//! \~english These executions are similar:
//! \~russian Эти вызовы будут идентичны:
//!
//! \~\code
//! a.out -cd -v 10
//! a.out --value 10 -dc
//! a.out -c -v 10 -d
//! a.out --console -d -v 10
//! a.out --debug -c --value 10
//! \endcode
//!
PILog::PILog(): PIThread(), log_ts(&log_file) {
setName("PILog");
split_time = 8_h;
timestamp_format = "yyyy-MM-dd hh:mm:ss.zzz";
setLineFormat("t - c: m");
id_by_cat[Level::Info] = PICout::registerExternalBufferID();
id_by_cat[Level::Debug] = PICout::registerExternalBufferID();
id_by_cat[Level::Warning] = PICout::registerExternalBufferID();
id_by_cat[Level::Error] = PICout::registerExternalBufferID();
CONNECTU(PICout::Notifier::object(), finished, this, coutDone);
}
PILog::~PILog() {
stop();
}
void PILog::setDir(const PIString & d) {
stopAndWait();
log_dir = d;
if (output[File]) {
PIDir::make(log_dir);
newFile();
}
start();
}
void PILog::setLineFormat(const PIString & f) {
line_format = f;
line_format_p = line_format;
line_format_p.replace("t", "${t}").replace("c", "${c}").replace("m", "${m}");
}
void PILog::setLevel(Level l) {
max_level = l;
}
PICout PILog::error(PIObject * context) {
return makePICout(context, Level::Error);
}
PICout PILog::warning(PIObject * context) {
return makePICout(context, Level::Warning);
}
PICout PILog::info(PIObject * context) {
return makePICout(context, Level::Info);
}
PICout PILog::debug(PIObject * context) {
return makePICout(context, Level::Debug);
}
void PILog::stop() {
while (true) {
log_mutex.lock();
bool done = queue.isEmpty();
log_mutex.unlock();
if (done) break;
piMinSleep();
}
PIThread::stopAndWait();
}
void PILog::coutDone(int id, PIString * buffer) {
if (!buffer) return;
if (!id_by_cat.containsValue(id)) return;
auto cat = id_by_cat.key(id, PILog::Level::Debug);
if (cat > max_level) return;
enqueue(*buffer, cat);
delete buffer;
}
PICout PILog::makePICout(PIObject * context, Level cat) {
auto buffer = new PIString();
if (context) {
*buffer = "["_a + context->className();
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
*buffer += "] ";
}
return PICout::withExternalBuffer(buffer, id_by_cat.value(cat), PICoutManipulators::AddSpaces);
}
void PILog::enqueue(const PIString & msg, Level cat) {
auto t = PIDateTime::fromSystemTime(PISystemTime::current());
PIMutexLocker ml(log_mutex);
queue.enqueue({cat, t, msg});
}
PIString PILog::entryToString(const Entry & e) const {
static PIStringList categories{"error", "warn ", "info ", "debug"};
PIString t = e.time.toString(timestamp_format);
PIString ret = line_format_p;
ret.replace("${t}", t).replace("${c}", categories[static_cast<int>(e.cat)]).replace("${m}", e.msg);
return ret;
}
void PILog::newFile() {
PIString aname = log_name;
if (aname.isNotEmpty()) aname += "__";
log_file.open(log_dir + "/" + aname + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss") + ".log." +
PIString::fromNumber(++part_number),
PIIODevice::ReadWrite);
}
void PILog::run() {
if (output[File]) {
if (split_tm.elapsed() >= split_time) {
split_tm.reset();
newFile();
}
}
log_mutex.lock();
if (queue.isEmpty()) {
log_mutex.unlock();
piMSleep(20);
return;
}
log_mutex.unlock();
while (true) {
log_mutex.lock();
if (queue.isEmpty()) {
log_mutex.unlock();
return;
}
auto qi = queue.dequeue();
log_mutex.unlock();
auto str = entryToString(qi);
if (log_file.isOpened()) log_ts << str << "\n";
if (output[Console]) {
PICout out(qi.cat == Level::Error ? piCerr : piCout);
if (color_console) {
switch (qi.cat) {
case Level::Error: out << PICoutManipulators::Red; break;
case Level::Warning: out << PICoutManipulators::Yellow; break;
default: break;
}
}
out << str;
}
}
}

View File

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

View File

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

View File

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

View File

@@ -1,60 +0,0 @@
/*! \file piclientserver_config.h
* \ingroup ClientServer
* \~\brief
* \~english
* \~russian
*/
/*
PIP - Platform Independent Primitives
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef piclientserver_config_H
#define piclientserver_config_H
#include "pibytearray.h"
#include "pip_client_server_export.h"
namespace PIClientServer {
class Server;
class Client;
class ClientBase;
class PIP_CLIENT_SERVER_EXPORT Config {
friend class Server;
friend class Client;
public:
void setPacketSign(ushort sign);
void setPacketSize(int bytes);
void enableSymmetricEncryption(const PIByteArray & key);
protected:
void apply(ClientBase * client);
PIByteArray crypt_key;
ushort packet_sign = 0xAFBE;
int packet_size = 1400;
private:
};
} // namespace PIClientServer
#endif

View File

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

View File

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

View File

@@ -32,30 +32,26 @@
//! \brief PICloudClient
class PIP_CLOUD_EXPORT PICloudClient
: public PIIODevice
, public PICloudBase {
PIIODEVICE(PICloudClient, "");
class PIP_CLOUD_EXPORT PICloudClient: public PIIODevice, public PICloudBase
{
PIIODEVICE(PICloudClient, "")
public:
explicit PICloudClient(const PIString & path = PIString(), PIIODevice::DeviceMode mode = PIIODevice::ReadWrite);
virtual ~PICloudClient();
void setServerName(const PIString & server_name);
void setKeepConnection(bool on);
bool isConnected() const { return is_connected; }
ssize_t bytesAvailable() const override { return buff.size(); }
void interrupt() override;
bool isConnected() const {return is_connected;}
EVENT(connected);
EVENT(disconnected);
EVENT(connected)
EVENT(disconnected)
protected:
bool openDevice() override;
bool closeDevice() override;
ssize_t readDevice(void * read_to, ssize_t max_size) override;
ssize_t writeDevice(const void * data, ssize_t size) override;
DeviceInfoFlags deviceInfoFlags() const override { return PIIODevice::Reliable; }
bool openDevice();
bool closeDevice();
int readDevice(void * read_to, int max_size);
int writeDevice(const void * data, int size);
DeviceInfoFlags deviceInfoFlags() const {return PIIODevice::Reliable;}
private:
EVENT_HANDLER1(void, _readed, PIByteArray &, data);

View File

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

View File

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

View File

@@ -26,9 +26,9 @@
#ifndef PICLOUDTCP_H
#define PICLOUDTCP_H
#include "pimutex.h"
#include "pip_cloud_export.h"
#include "pistring.h"
#include "pimutex.h"
class PIEthernet;
@@ -37,6 +37,7 @@ class PIStreamPacker;
namespace PICloud {
class PIP_CLOUD_EXPORT TCP {
public:
enum Version {
@@ -60,7 +61,7 @@ public:
TCP(PIStreamPacker * s);
void setRole(Role r);
Role role() const { return (Role)header.role; }
Role role() const {return (Role)header.role;}
void setServerName(const PIString & server_name_);
PIString serverName() const;
@@ -90,8 +91,9 @@ private:
PIString server_name;
PIStreamPacker * streampacker;
PIMutex mutex_send;
};
} // namespace PICloud
}
#endif // PICLOUDTCP_H

View File

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

View File

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

View File

@@ -35,11 +35,9 @@
//!
//! \~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

View File

@@ -20,6 +20,7 @@
#include "picodeparser.h"
PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIStringList arg_vals;
while (!args_.isEmpty()) {
@@ -31,32 +32,29 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
PIString ca;
if (bi >= 0 && bi < ci) {
ca = args_.left(args_.takeLeft(bi).toInt());
ci -= ca.size_s();
bi -= ca.size_s();
ci -= ca.size_s(); bi -= ca.size_s();
ca += '(' + args_.takeRange('(', ')') + ')';
} else {
ca = args_.takeLeft(ci);
}
arg_vals << ca;
args_.trim();
args_.takeLeft(1);
args_.trim();
args_.trim(); args_.takeLeft(1); args_.trim();
}
if (args.size() != arg_vals.size()) {
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect") << args.size() << "arguments but takes"
<< arg_vals.size() << "!";
piCout << ("Error: in expansion of macro \"" + name + '(' + args.join(", ") + ")\": expect")
<< args.size() << "arguments but takes" << arg_vals.size() << "!";
if (ok != 0) *ok = false;
return PIString();
}
PIString ret = value;
for (int i = 0; i < args.size_s(); ++i) {
const PIString &an(args[i]), av(arg_vals[i]);
const PIString & an(args[i]), av(arg_vals[i]);
int ind(-1);
while ((ind = ret.find(an, ind + 1)) >= 0) {
PIChar ppc, pc, nc;
if (ind > 1) ppc = ret[ind - 2];
if (ind > 0) pc = ret[ind - 1];
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(), 1)[0];
if (ind + an.size_s() < ret.size_s()) nc = ret.mid(ind + an.size_s(),1)[0];
if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars
ind--;
ret.replace(ind, an.size_s() + 1, '\"' + av + '\"');
@@ -74,6 +72,7 @@ PIString PICodeParser::Macro::expand(PIString args_, bool * ok) const {
}
PICodeParser::PICodeParser() {
macros_iter = 32;
with_includes = true;
@@ -119,7 +118,7 @@ void PICodeParser::parseFile(const PIString & file, bool follow_includes) {
void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes) {
clear();
piForeachC(PIString & f, files)
piForeachC (PIString & f, files)
parseFileInternal(f, follow_includes);
/*piCout << "\n\nDefines:";
piForeachC (Define & m, defines)
@@ -139,14 +138,10 @@ void PICodeParser::parseFiles(const PIStringList & files, bool follow_includes)
}
void PICodeParser::parseFileContent(PIString fc) {
parseFileContent(fc, false);
}
bool PICodeParser::isEnum(const PIString & name) {
piForeachC(Enum & e, enums)
if (e.name == name) return true;
piForeachC (Enum & e, enums)
if (e.name == name)
return true;
return false;
}
@@ -159,14 +154,14 @@ bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes
int ii = 0;
while (!f.isOpened() && ii < (includes.size_s() - 1)) {
f.setPath(includes[++ii] + '/' + file);
// piCout << "try" << f.path();
//piCout << "try" << f.path();
f.open(PIIODevice::ReadOnly);
}
if (!f.isOpened()) {
piCout << ("Error: can`t open file \"" + file + "\"!");
return false;
}
// piCout << "add" << file;
//piCout << "add" << file;
proc_files << f.path();
PIString fc = PIString::fromUTF8(f.readAll());
piCout << "parsing" << f.path() << "...";
@@ -179,8 +174,7 @@ bool PICodeParser::parseFileInternal(const PIString & file, bool follow_includes
void PICodeParser::clear() {
piForeach(Entity * i, entities)
delete i;
piForeach (Entity * i, entities) delete i;
defines.clear();
macros.clear();
enums.clear();
@@ -193,142 +187,37 @@ void PICodeParser::clear() {
cur_def_vis = Global;
anon_num = 0;
PIStringList defs = PIStringAscii(PICODE_DEFINES).split(",");
piForeachC(PIString & d, defs)
piForeachC (PIString & d, defs)
defines << Define(d, "");
defines << Define(PIStringAscii("PICODE"), "") << custom_defines;
macros << Macro(PIStringAscii("PIOBJECT"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PIOBJECT_PARENT"), "", PIStringList() << "parent")
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"),
"",
PIStringList() << "name"
<< "parent")
<< Macro(PIStringAscii("PIOBJECT_SUBCLASS"), "", PIStringList() << "name" << "parent")
<< Macro(PIStringAscii("PIIODEVICE"), "", PIStringList() << "name")
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name") << Macro(PIStringAscii("PRIVATE_DECLARATION"))
<< Macro(PIStringAscii("NO_COPY_CLASS"), "", PIStringList() << "name")
<< Macro(PIStringAscii("PRIVATE_DECLARATION"))
<< Macro(PIStringAscii("EVENT"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT" ), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("EVENT0"), "void name();", PIStringList() << "name")
<< Macro(PIStringAscii("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("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_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");
<< 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")
;
}
@@ -358,8 +247,7 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (i > 0) pc = c;
c = fc[i].toAscii();
if (c == '"' && !mlc && pc != '\'') {
if (i > 0)
if (fc[i - 1] == '\\') continue;
if (i > 0) if (fc[i - 1] == '\\') continue;
cc = !cc;
continue;
}
@@ -370,24 +258,9 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
continue;
}
if (cc) continue;
if (fc.mid(i, 2) == "/*") {
mlc = true;
mls = i;
++i;
continue;
}
if (fc.mid(i, 2) == "*/" && mlc) {
mlc = false;
fc.cutMid(mls, i - mls + 2);
i = mls - 1;
continue;
}
if (fc.mid(i, 2) == "//" && !mlc) {
ole = fc.find('\n', i);
fc.cutMid(i, ole < 0 ? -1 : ole - i);
--i;
continue;
}
if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;}
if (fc.mid(i, 2) == "*/" && mlc) {mlc = false; fc.cutMid(mls, i - mls + 2); i = mls - 1; continue;}
if (fc.mid(i, 2) == "//" && !mlc) {ole = fc.find('\n', i); fc.cutMid(i, ole < 0 ? -1 : ole - i); --i; continue;}
}
pfc = procMacros(fc);
@@ -396,34 +269,33 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
bool replaced = true;
int replaced_cnt = 0;
while (replaced) {
// piCout << "MACRO iter" << replaced_cnt;
//piCout << "MACRO iter" << replaced_cnt;
if (replaced_cnt >= macros_iter) {
piCout << "Error: recursive macros detected!";
break; // return false;
break;//return false;
}
replaced_cnt++;
replaced = false;
piForeachC(Define & d, defines) {
piForeachC (Define & d, defines) {
int ind(-1);
while ((ind = pfc.find(d.first, ind + 1)) >= 0) {
PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1];
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(), 1)[0];
if (ind + d.first.size_s() < pfc.size_s()) nc = pfc.mid(ind + d.first.size_s(),1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
pfc.replace(ind, d.first.size_s(), d.second);
ind -= d.first.size_s() - d.second.size_s();
replaced = true;
}
}
piForeachC(Macro & m, macros) {
piForeachC (Macro & m, macros) {
int ind(-1);
while ((ind = pfc.find(m.name, ind + 1)) >= 0) {
PIChar pc, nc;
if (ind > 0) pc = pfc[ind - 1];
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(), 1)[0];
if (ind + m.name.size_s() < pfc.size_s()) nc = pfc.mid(ind + m.name.size_s(),1)[0];
if (_isCChar(pc) || _isCChar(nc) || nc.isDigit()) continue;
PIString ret, range;
bool ok(false);
PIString ret, range; bool ok(false);
range = pfc.mid(ind + m.name.size_s()).takeRange('(', ')');
ret = m.expand(range, &ok);
if (!ok) return false;
@@ -437,9 +309,8 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
replaceMeta(pfc);
// piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
//piCout << PICoutManipulators::NewLine << "file" << cur_file << pfc;
int pl = -1;
cur_def_vis = Global;
while (!pfc.isEmpty()) {
pfc.trim();
int nl = pfc.size_s();
@@ -450,7 +321,6 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += pfc.takeCWord() + s_ns;
ccmn = pfc.takeRange('{', '}');
// piCout << "namespace" << cur_namespace;
parseClass(0, ccmn, true);
cur_namespace = prev_namespace;
continue;
@@ -460,25 +330,14 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
pfc.takeRange('<', '>');
bool def = !isDeclaration(pfc, 0, &end);
pfc.cutLeft(end);
if (def)
pfc.takeRange('{', '}');
else
pfc.takeSymbol();
if (def) pfc.takeRange('{', '}');
else pfc.takeSymbol();
continue;
}
if (pfc.left(5) == s_class || pfc.left(6) == s_struct || pfc.left(5) == s_union) {
int dind = pfc.find('{', 0), find = pfc.find(';', 0);
// piCout << pfc.left(6) << dind << find;
if (dind < 0 && find < 0) {
pfc.cutLeft(6);
continue;
}
if (dind < 0 || find < dind) {
// piCout << "skip FC" << (find + 1) << pfc.left(find + 1);
pfc.cutLeft(find + 1);
// pfc.cutLeft(6);
continue;
}
if (dind < 0 && find < 0) {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;
pfc.remove(0, ccmn.size());
parseClass(0, ccmn, false);
@@ -489,12 +348,6 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
tmp = pfc.takeCWord();
pfc.trim();
MetaMap meta = maybeMeta(pfc);
if (tmp == s_class || tmp == s_struct) {
tmp = pfc.takeCWord();
pfc.trim();
MetaMap smeta = maybeMeta(pfc);
meta << smeta;
}
parseEnum(0, cur_namespace + tmp, pfc.takeRange('{', '}'), meta);
pfc.takeSymbol();
continue;
@@ -502,10 +355,8 @@ bool PICodeParser::parseFileContent(PIString & fc, bool main) {
if (pfc.left(7) == s_typedef) {
pfc.cutLeft(7);
typedefs << parseTypedef(pfc.takeLeft(pfc.find(';')));
if (typedefs.back().first.isEmpty())
typedefs.pop_back();
else
root_.typedefs << typedefs.back();
if (typedefs.back().first.isEmpty()) typedefs.pop_back();
else root_.typedefs << typedefs.back();
pfc.takeSymbol();
continue;
}
@@ -539,41 +390,35 @@ PICodeParser::Entity * PICodeParser::parseClassDeclaration(const PIString & fc)
meta = tmp_meta.value(cd.takeMid(ind, 5));
cd.replaceAll(s_ss, ' ');
}
// piCout << "found class <****\n" << cd << "\n****>";
//piCout << "found class <****\n" << cd << "\n****>";
ind = cd.find(':');
PIVector<Entity *> parents;
PIVector<Entity * > parents;
if (ind > 0) {
PIStringList pl = cd.takeMid(ind + 1).trim().split(',');
cd.cutRight(1);
Entity * pe = 0;
piForeachC(PIString & p, pl) {
if (p.contains(' '))
pn = p.mid(p.find(' ') + 1);
else
pn = p;
piForeachC (PIString & p, pl) {
if (p.contains(' ')) pn = p.mid(p.find(' ') + 1);
else pn = p;
pe = findEntityByName(pn);
if (pe == 0)
; //{piCout << "Error: can`t find" << pn;}
else
parents << pe;
if (pe == 0) ;//{piCout << "Error: can`t find" << pn;}
else parents << pe;
}
}
PIString typename_ = cd.left(6).trim();
bool is_class = typename_ == s_class;
Visibility vis = cur_def_vis;
cur_def_vis = (is_class ? Private : Public);
PIString cn = cd.mid(6).trim();
bool has_name = !cn.isEmpty();
if (cn.isEmpty()) cn = PIStringAscii("<unnamed_") + PIString::fromNumber(anon_num++) + '>';
// piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return nullptr;
//piCout << "found " << typename_ << cn;
if (cn.isEmpty()) return 0;
Entity * e = new Entity();
e->meta = meta;
e->name = cur_namespace + cn;
e->type = typename_;
e->has_name = has_name;
e->parents = parents;
e->visibility = vis;
e->file = cur_file;
entities << e;
return e;
@@ -596,13 +441,18 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
Visibility prev_vis = cur_def_vis;
int dind = fc.find('{'), find = fc.find(';'), end = 0;
if (dind < 0 && find < 0) return;
// piCout << "parse class <****\n" << fc << "\n****>";
if (dind < 0 || find < dind) {
fc.left(find);
return;
}
//piCout << "parse class <****\n" << fc << "\n****>";
Entity * ce = parent;
if (!is_namespace) {
ce = parseClassDeclaration(fc.takeLeft(dind));
fc.trim().cutLeft(1).cutRight(1).trim();
}
// piCout << "found class <****\n" << fc << "\n****>";
//piCout << "found class <****\n" << fc << "\n****>";
///if (!ce) return PIString();
if (ce) {
if (parent) parent->children << ce;
ce->parent_scope = parent;
@@ -611,26 +461,14 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
bool def = false;
PIString prev_namespace = cur_namespace, stmp;
if (ce) cur_namespace += ce->name + s_ns;
// piCout << "parse class" << ce->name << "namespace" << cur_namespace;
// piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
//piCout << "parse class" << ce->name << "namespace" << cur_namespace;
//piCout << "\nparse class" << ce->name << "namespace" << cur_namespace;
while (!fc.isEmpty()) {
PIString cw = fc.takeCWord(), tmp;
// piCout << "\ntaked word" << cw;
if (cw == s_public) {
cur_def_vis = Public;
fc.cutLeft(1);
continue;
}
if (cw == s_protected) {
cur_def_vis = Protected;
fc.cutLeft(1);
continue;
}
if (cw == s_private) {
cur_def_vis = Private;
fc.cutLeft(1);
continue;
}
//piCout << "\ntaked word" << cw;
if (cw == s_public ) {cur_def_vis = Public; fc.cutLeft(1); continue;}
if (cw == s_protected) {cur_def_vis = Protected; fc.cutLeft(1); continue;}
if (cw == s_private ) {cur_def_vis = Private; fc.cutLeft(1); continue;}
if (cw == s_namespace) {
PIString prev_namespace = cur_namespace, ccmn;
cur_namespace += fc.takeCWord() + s_ns;
@@ -640,7 +478,6 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
continue;
}
if (cw == s_class || cw == s_struct || cw == s_union) {
// piCout << cw << isDeclaration(fc, 0, &end);
if (isDeclaration(fc, 0, &end)) {
fc.cutLeft(end);
fc.takeSymbol();
@@ -657,26 +494,18 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
tmp = fc.takeCWord();
fc.trim();
MetaMap meta = maybeMeta(fc);
if (tmp == s_class || tmp == s_struct) {
tmp = fc.takeCWord();
fc.trim();
MetaMap smeta = maybeMeta(fc);
meta << smeta;
}
parseEnum(ce, cur_namespace + tmp, fc.takeRange('{', '}'), meta);
fc.takeSymbol();
continue;
}
if (cw == s_friend) {
fc.cutLeft(fc.find(';') + 1);
continue;
}
if (cw == s_friend) {fc.cutLeft(fc.find(';') + 1); continue;}
if (cw == s_typedef) {
if (ce) {
ce->typedefs << parseTypedef(fc.takeLeft(fc.find(';')));
typedefs << ce->typedefs.back();
typedefs.back().first.insert(0, cur_namespace);
if (ce->typedefs.back().first.isEmpty()) ce->typedefs.pop_back();
if (ce->typedefs.back().first.isEmpty())
ce->typedefs.pop_back();
}
fc.takeSymbol();
continue;
@@ -685,22 +514,17 @@ void PICodeParser::parseClass(Entity * parent, PIString & fc, bool is_namespace)
fc.takeRange('<', '>');
def = !isDeclaration(fc, 0, &end);
fc.cutLeft(end);
if (def)
fc.takeRange('{', '}');
else
fc.takeSymbol();
if (def) fc.takeRange('{', '}');
else fc.takeSymbol();
continue;
}
def = !isDeclaration(fc, 0, &end);
tmp = (cw + fc.takeLeft(end)).trim();
if (!tmp.isEmpty() && ce) parseMember(ce, tmp);
if (def)
fc.takeRange('{', '}');
else
fc.takeSymbol();
if (ps == fc.size_s()) {
fc.cutLeft(1);
}
if (!tmp.isEmpty() && ce)
parseMember(ce, tmp);
if (def) fc.takeRange('{', '}');
else fc.takeSymbol();
if (ps == fc.size_s()) {fc.cutLeft(1);}
ps = fc.size_s();
}
cur_def_vis = prev_vis;
@@ -712,7 +536,7 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
PICodeParser::MetaMap ret;
if (fc.isEmpty()) return ret;
PIStringList ml = fc.split(',');
piForeachC(PIString & m, ml) {
piForeachC (PIString & m, ml) {
int i = m.find('=');
if (i < 0) {
ret[m.trimmed()] = PIString();
@@ -723,7 +547,7 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
ret[m.left(i).trim()] = mv;
}
}
// piCout << ms << ret;
//piCout << ms << ret;
return ret;
}
@@ -731,53 +555,47 @@ PICodeParser::MetaMap PICodeParser::parseMeta(PIString & fc) {
bool PICodeParser::parseEnum(Entity * parent, const PIString & name, PIString fc, const MetaMap & meta) {
static const PIString s_ss = PIStringAscii(" ");
static const PIString s_M = PIStringAscii("$M");
// piCout << PIStringAscii("enum") << name << fc;
//piCout << PIStringAscii("enum") << name << fc;
Enum e(name);
e.meta = meta;
PIStringList vl(fc.split(','));
PIString vn;
int cv = -1, ind = 0;
piForeach(PIString & v, vl) {
piForeach (PIString & v, vl) {
MetaMap meta;
int mi = v.find(s_M);
if (mi >= 0) {
meta = tmp_meta.value(v.takeMid(mi, 5));
v.replaceAll(s_ss, ' ');
}
vn = v;
ind = v.find('=');
if (ind > 0) {
cv = v.right(v.size_s() - ind - 1).toInt();
vn = v.left(ind);
}
vn = v; ind = v.find('=');
if (ind > 0) {cv = v.right(v.size_s() - ind - 1).toInt(); vn = v.left(ind);}
if (ind < 0) ++cv;
e.members << EnumeratorInfo(vn.trim(), cv, meta);
}
if (!e.members.isEmpty())
if (e.members.back().name.isEmpty()) e.members.pop_back();
if (e.members.back().name.isEmpty())
e.members.pop_back();
enums << e;
return true;
}
PICodeParser::Typedef PICodeParser::parseTypedef(PIString fc) {
// piCout << "parse typedef" << fc;
//piCout << "parse typedef" << fc;
Typedef td;
fc.replaceAll('\t', ' ');
if (fc.contains('(')) {
int start = fc.find('('), end = fc.find(')');
td.first = fc.takeMid(start + 1, end - start - 1).trim();
if (td.first.left(1) == PIChar('*')) {
td.first.cutLeft(1).trim();
fc.insert(start + 1, '*');
}
if (td.first.left(1) == PIChar('*')) {td.first.cutLeft(1).trim(); fc.insert(start + 1, '*');}
td.second = fc.trim();
} else {
td.first = fc.takeMid(fc.findLast(' ')).trim();
td.second = fc.trim();
}
// piCout << "found typedef" << td;
//piCout << "found typedef" << td;
return td;
}
@@ -813,26 +631,22 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
if (fc.trim().isEmpty()) return true;
if (fc.find(s_operator) >= 0) return true;
tmp_temp.clear();
// piCout << "parse member" << fc;
//piCout << "parse member" << fc;
int ts = fc.find('<'), te = 0;
PIString ctemp, crepl;
while (ts >= 0) {
ctemp = fc.mid(ts).takeRange('<', '>');
if (ctemp.isEmpty()) {
te = ts + 1;
ts = fc.find('<', te);
continue;
}
if (ctemp.isEmpty()) {te = ts + 1; ts = fc.find('<', te); continue;}
crepl = s_T + PIString::fromNumber(tmp_temp.size_s()).expandLeftTo(3, '0');
fc.replace(ts, ctemp.size_s() + 2, crepl);
tmp_temp[crepl] = '<' + ctemp + '>';
ts = fc.find('<', te);
}
fc.replaceAll('\n', ' ').replaceAll('\t', ' ').replaceAll(s_ss, ' ').replaceAll(s_cs, ',').replaceAll(s_sb, '(').replaceAll(s_sM, s_M);
// piCout << "parse member" << fc;
//piCout << "parse member" << fc;
PIStringList tl, al;
Member me;
// piCout << fc;
//piCout << fc;
if (fc.contains('(')) {
MetaMap meta;
int ind = fc.find(s_M);
@@ -842,10 +656,10 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
}
fc.cutRight(fc.size_s() - fc.findLast(')') - 1);
te = fc.find('(');
// piCout << fc;
//piCout << fc;
for (ts = te - 1; ts >= 0; --ts)
if (!_isCChar(fc[ts]) && !(fc[ts].isDigit())) break;
// piCout << "takeMid" << ts + 1 << te - ts - 1;
//piCout << "takeMid" << ts + 1 << te - ts - 1;
me.meta = meta;
me.name = fc.takeMid(ts + 1, te - ts - 1);
if (me.name == parent->name) return true;
@@ -866,18 +680,20 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
}
normalizeEntityNamespace(me.type);
int i = 0;
// piCout << me.arguments_full;
piForeach(PIString & a, me.arguments_full)
if ((i = a.find('=')) > 0) a.cutRight(a.size_s() - i).trim();
//piCout << me.arguments_full;
piForeach (PIString & a, me.arguments_full)
if ((i = a.find('=')) > 0)
a.cutRight(a.size_s() - i).trim();
for (int j = 0; j < me.arguments_full.size_s(); ++j)
if (me.arguments_full[j] == s_void) {
me.arguments_full.remove(j);
--j;
}
me.arguments_type = me.arguments_full;
piForeach(PIString & a, me.arguments_type) {
piForeach (PIString & a, me.arguments_type) {
crepl.clear();
if (a.contains('[')) crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
if (a.contains('['))
crepl = a.takeMid(a.find('['), a.findLast(']') - a.find('[') + 1);
for (ts = a.size_s() - 1; ts >= 0; --ts)
if (!_isCChar(a[ts]) && !(a[ts].isDigit())) break;
a.cutRight(a.size_s() - ts - 1);
@@ -886,18 +702,18 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
a.trim();
}
restoreTmpTemp(&me);
// piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
//piCout << "func" << me.type << me.name << me.arguments_full << me.arguments_type;
parent->functions << me;
} else {
if (fc.endsWith(';')) fc.cutRight(1);
// piCout << "member" << fc;
//piCout << "member" << fc;
if (fc.startsWith(s_using) || !(fc.contains(' ') || fc.contains('\t') || fc.contains('\n'))) return true;
int bits = extractMemberBits(fc);
tl = fc.split(',');
// piCout << "member" << fc << tl;
// piCout << "member after eb" << fc << ", bits =" << bits;
//piCout << "member" << fc << tl;
//piCout << "member after eb" << fc << ", bits =" << bits;
if (tl.isEmpty()) return true;
piForeach(PIString & v, tl)
piForeach (PIString & v, tl)
removeAssignment(v);
bool vn = true;
ctemp = tl.front().trim();
@@ -907,11 +723,8 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
ctemp.trim();
}
for (ts = ctemp.size_s() - 1; ts > 0; --ts) {
if (vn) {
if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;
} else {
if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;
}
if (vn) {if (!_isCChar(ctemp[ts]) && !ctemp[ts].isDigit() && ctemp[ts] != '[' && ctemp[ts] != ']') vn = false;}
else {if (_isCChar(ctemp[ts]) || ctemp[ts].isDigit()) break;}
}
me.type = ctemp.takeLeft(ts + 1);
me.visibility = cur_def_vis;
@@ -941,21 +754,21 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
type.trim();
normalizeEntityNamespace(type);
tl[0] = ctemp.trim();
// piCout << "vars" << tl;
piForeachC(PIString & v, tl) {
//piCout << "vars" << tl;
piForeachC (PIString & v, tl) {
crepl.clear();
me.name = v.trimmed();
me.type = type;
restoreTmpMeta(&me);
if (me.name.isEmpty()) continue;
if (me.name.contains('[')) crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
if (me.name.contains('['))
crepl = me.name.takeMid(me.name.find('['), me.name.findLast(']') - me.name.find('[') + 1);
while (!me.name.isEmpty()) {
if (me.name.front() == PIChar('*') || me.name.front() == PIChar('&')) {
me.type += me.name.takeLeft(1);
me.name.trim();
} else
break;
} else break;
}
me.is_type_ptr = (me.type.right(1) == PIChar(']') || me.type.right(1) == PIChar('*'));
me.type += crepl;
@@ -965,12 +778,12 @@ bool PICodeParser::parseMember(Entity * parent, PIString & fc) {
if (cdim.isEmpty()) break;
me.dims << cdim;
}
// PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
// piCout << "var" << v << me.type << me.name << me.bits;
//PICout(PICoutManipulators::AddAll) << "var" << me.type << me.name << me.bits;
//piCout << "var" << v << me.type << me.name << me.bits;
parent->members << me;
}
}
// piCout << "parse member" << fc;
//piCout << "parse member" << fc;
return true;
}
@@ -1002,25 +815,13 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
break;
}
n.push_front(' ');
if (n.find(s_s_const_s) >= 0) {
n.replaceAll(s_s_const_s, "");
pref += s_const_s;
}
if (n.find(s_s_static_s) >= 0) {
n.replaceAll(s_s_static_s, "");
pref += s_static_s;
}
if (n.find(s_s_mutable_s) >= 0) {
n.replaceAll(s_s_mutable_s, "");
pref += s_mutable_s;
}
if (n.find(s_s_volatile_s) >= 0) {
n.replaceAll(s_s_volatile_s, "");
pref += s_volatile_s;
}
if (n.find(s_s_const_s) >= 0) {n.replaceAll(s_s_const_s, ""); pref += s_const_s;}
if (n.find(s_s_static_s) >= 0) {n.replaceAll(s_s_static_s, ""); pref += s_static_s;}
if (n.find(s_s_mutable_s) >= 0) {n.replaceAll(s_s_mutable_s, ""); pref += s_mutable_s;}
if (n.find(s_s_volatile_s) >= 0) {n.replaceAll(s_s_volatile_s, ""); pref += s_volatile_s;}
n.trim();
int f = 0;
piForeachC(Entity * e, entities) {
piForeachC (Entity * e, entities) {
if (e->name == n) {
n = (pref + n + suff).trim();
return;
@@ -1032,20 +833,20 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
return;
}
}
piForeachC(Enum & e, enums) {
piForeachC (Enum & e, enums) {
if ((f = e.name.find(n)) >= 0)
if (e.name.at(f - 1) == PIChar(':'))
if (e.name.find(cur_namespace) >= 0) {
// piCout << "change" << n << "to" << e.name + suff;
//piCout << "change" << n << "to" << e.name + suff;
n = pref + e.name + suff;
return;
}
}
piForeachC(Typedef & e, typedefs) {
piForeachC (Typedef & e, typedefs) {
if ((f = e.first.find(n)) >= 0)
if (e.first.at(f - 1) == PIChar(':'))
if (e.first.find(cur_namespace) >= 0) {
// piCout << "change" << n << "to" << e.name + suff;
//piCout << "change" << n << "to" << e.name + suff;
n = pref + e.first + suff;
return;
}
@@ -1057,11 +858,11 @@ void PICodeParser::normalizeEntityNamespace(PIString & n) {
void PICodeParser::restoreTmpTemp(Member * e) {
static const PIString s_T = PIStringAscii("$T");
int i = 0;
piForeach(PIString & a, e->arguments_full) {
piForeach (PIString & a, e->arguments_full) {
while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
}
piForeach(PIString & a, e->arguments_type) {
piForeach (PIString & a, e->arguments_type) {
while ((i = a.find(s_T)) >= 0)
a.replace(i, 5, tmp_temp[a.mid(i, 5)]);
}
@@ -1094,7 +895,7 @@ bool PICodeParser::macroCondition(const PIString & mif, PIString mifcond) {
static const PIString s_ifndef = PIStringAscii("ifndef");
static const PIString s_if = PIStringAscii("if");
static const PIString s_elif = PIStringAscii("elif");
// piCout << "macroCondition" << mif << mifcond;
//piCout << "macroCondition" << mif << mifcond;
if (mif == s_ifdef) return isDefineExists(mifcond);
if (mif == s_ifndef) return !isDefineExists(mifcond);
if (mif == s_if || mif == s_elif) {
@@ -1113,29 +914,14 @@ double PICodeParser::procMacrosCond(PIString fc) {
char cc, nc;
PIString ce;
fc.removeAll(s_defined);
// piCout << "procMacrosCond" << fc;
//piCout << "procMacrosCond" << fc;
while (!fc.isEmpty()) {
cc = fc[0].toAscii();
nc = (fc.size() > 1 ? fc[1].toAscii() : 0);
if (cc == '!') {
neg = true;
fc.pop_front();
continue;
}
if (cc == '(') {
br = true;
brv = procMacrosCond(fc.takeRange('(', ')'));
}
if (cc == '&' && nc == '&') {
fc.remove(0, 2);
oper = 1;
continue;
}
if (cc == '|' && nc == '|') {
fc.remove(0, 2);
oper = 2;
continue;
}
if (cc == '!') {neg = true; fc.pop_front(); continue;}
if (cc == '(') {br = true; brv = procMacrosCond(fc.takeRange('(', ')'));}
if (cc == '&' && nc == '&') {fc.remove(0, 2); oper = 1; continue;}
if (cc == '|' && nc == '|') {fc.remove(0, 2); oper = 2; continue;}
if (!br) {
ce = fc.takeCWord();
if (ce.isEmpty()) ce = fc.takeNumber();
@@ -1145,7 +931,7 @@ double PICodeParser::procMacrosCond(PIString fc) {
ret = br ? brv : defineValue(ce);
if (neg) ret = -ret;
} else {
// piCout << "oper" << oper << "with" << ce;
//piCout << "oper" << oper << "with" << ce;
if (!br) brv = defineValue(ce);
switch (oper) {
case 1: ret = ret && (neg ? -brv : brv); break;
@@ -1156,22 +942,24 @@ double PICodeParser::procMacrosCond(PIString fc) {
ps = fc.size_s();
br = neg = false;
}
// piCout << "return" << ret;
//piCout << "return" << ret;
return ret;
}
bool PICodeParser::isDefineExists(const PIString & dn) {
piForeachC(Define & d, defines) {
if (d.first == dn) return true;
piForeachC (Define & d, defines) {
if (d.first == dn)
return true;
}
return false;
}
double PICodeParser::defineValue(const PIString & dn) {
piForeachC(Define & d, defines) {
if (d.first == dn) return d.second.isEmpty() ? 1. : d.second.toDouble();
piForeachC (Define & d, defines) {
if (d.first == dn)
return d.second.isEmpty() ? 1. : d.second.toDouble();
}
return dn.toDouble();
}
@@ -1190,7 +978,7 @@ void PICodeParser::replaceMeta(PIString & dn) {
PIString meta = dn.mid(ms, ml).trim();
PIString rm = s_M + PIString::fromNumber(tmp_meta.size_s()).expandLeftTo(3, '0');
dn.replace(s, ms + ml + 1 - s, rm);
// piCout << "FOUND META \"" << meta << '\"';
//piCout << "FOUND META \"" << meta << '\"';
tmp_meta[rm] = parseMeta(meta);
s = dn.find(s_PIMETA);
}
@@ -1198,23 +986,18 @@ void PICodeParser::replaceMeta(PIString & dn) {
PICodeParser::Entity * PICodeParser::findEntityByName(const PIString & en) {
piForeach(Entity * e, entities)
if (e->name == en) return e;
piForeach (Entity * e, entities)
if (e->name == en)
return e;
return 0;
}
bool PICodeParser::isDeclaration(const PIString & fc, int start, int * end) {
int dind = fc.find('{', start), find = fc.find(';', start);
// piCout << "isDeclaration" << dind << find << fc.left(10);
if (dind < 0 && find < 0) {
if (end) *end = -1;
return true;
}
if (dind < 0 || find < dind) {
if (end) *end = find;
return true;
}
//piCout << "isDeclaration" << dind << find << fc.left(10);
if (dind < 0 && find < 0) {if (end) *end = -1; return true;}
if (dind < 0 || find < dind) {if (end) *end = find; return true;}
if (end) *end = dind;
return false;
}
@@ -1252,80 +1035,68 @@ PIString PICodeParser::procMacros(PIString fc) {
int ifcnt = 0;
bool grab = false, skip = false, cond_ok = false;
PIString pfc, nfc, line, mif, mifcond;
// piCout << "procMacros\n<******" << fc << "\n******>";
//piCout << "procMacros\n<******" << fc << "\n******>";
fc += '\n';
while (!fc.isEmpty()) {
line = fc.takeLine().trimmed();
if (line.left(1) == PIChar('#')) {
mifcond = line.mid(1);
mif = mifcond.takeCWord();
// piCout << mif;
// piCout << "mif mifcond" << mif << mifcond << ifcnt;
//piCout << mif;
//piCout << "mif mifcond" << mif << mifcond << ifcnt;
if (skip || grab) {
if (mif.left(2) == s_if) ifcnt++;
if (mif.left(5) == s_endif) {
if (ifcnt > 0)
ifcnt--;
if (ifcnt > 0) ifcnt--;
else {
// piCout << "main endif" << skip << grab;
if (grab) pfc += procMacros(nfc);
//piCout << "main endif" << skip << grab;
if (grab) pfc << procMacros(nfc);
skip = grab = false;
continue;
}
}
if (mif.left(4) == s_elif && ifcnt == 0) {
// piCout << "main elif" << skip << grab << cond_ok;
//piCout << "main elif" << skip << grab << cond_ok;
if (cond_ok) {
if (grab) {
pfc += procMacros(nfc);
skip = true;
grab = false;
pfc << procMacros(nfc);
skip = true; grab = false;
}
continue;
}
if (skip) {
// piCout << "check elif" << skip << grab << cond_ok;
//piCout << "check elif" << skip << grab << cond_ok;
if (!macroCondition(mif, mifcond.trimmed())) continue;
// piCout << "check elif ok";
skip = false;
grab = cond_ok = true;
//piCout << "check elif ok";
skip = false; grab = cond_ok = true;
continue;
}
continue;
}
if (mif.left(4) == s_else && ifcnt == 0) {
// piCout << "main else" << skip << grab;
if (grab) pfc += procMacros(nfc);
if (skip && !cond_ok) {
skip = false;
grab = true;
} else {
skip = true;
grab = false;
}
//piCout << "main else" << skip << grab;
if (grab) pfc << procMacros(nfc);
if (skip && !cond_ok) {skip = false; grab = true;}
else {skip = true; grab = false;}
continue;
}
if (grab) nfc += line + '\n';
if (grab) nfc << line << '\n';
continue;
}
if (mif.left(2) == s_if) {
// piCout << "main if";
//piCout << "main if";
skip = grab = cond_ok = false;
if (macroCondition(mif, mifcond.trimmed()))
grab = cond_ok = true;
else
skip = true;
if (macroCondition(mif, mifcond.trimmed())) grab = cond_ok = true;
else skip = true;
ifcnt = 0;
nfc.clear();
} else {
parseDirective(line.cutLeft(1).trim());
// return false; /// WARNING: now skip errors
//return false; /// WARNING: now skip errors
}
} else {
if (grab)
nfc += line + '\n';
else if (!skip)
pfc += line + '\n';
if (grab) nfc << line << '\n';
else if (!skip) pfc << line << '\n';
}
}
return pfc;
@@ -1339,7 +1110,7 @@ bool PICodeParser::parseDirective(PIString d) {
static const PIString s_PIMETA = PIStringAscii("PIMETA");
if (d.isEmpty()) return true;
PIString dname = d.takeCWord();
// piCout << "parseDirective" << d;
//piCout << "parseDirective" << d;
if (dname == s_include) {
d.replaceAll('<', '\"').replaceAll('>', '\"');
PIString cf = cur_file, ifc = d.takeRange('\"', '\"');
@@ -1351,7 +1122,7 @@ bool PICodeParser::parseDirective(PIString d) {
}
if (dname == s_define) {
PIString mname = d.takeCWord();
// piCout << mname;
//piCout << mname;
if (mname == s_PIMETA) return true;
if (d.left(1) == PIChar('(')) { // macro
PIStringList args = d.takeRange('(', ')').split(',').trim();
@@ -1376,10 +1147,7 @@ bool PICodeParser::parseDirective(PIString d) {
if (dname == s_undef) {
PIString mname = d.takeCWord();
for (int i = 0; i < defines.size_s(); ++i)
if (defines[i].first == mname) {
defines.remove(i);
--i;
}
if (defines[i].first == mname) {defines.remove(i); --i;}
return true;
}
return true;

View File

@@ -26,27 +26,17 @@
#ifndef PICODEPARSER_H
#define PICODEPARSER_H
#include "pievaluator.h"
#include "pifile.h"
#include "pievaluator.h"
inline bool _isCChar(const PIChar & c) {
return (c.isAlpha() || (c.toAscii() == '_'));
}
inline bool _isCChar(const PIString & c) {
if (c.isEmpty()) return false;
return _isCChar(c[0]);
}
inline bool _isCChar(const PIChar & c) {return (c.isAlpha() || (c.toAscii() == '_'));}
inline bool _isCChar(const PIString & c) {if (c.isEmpty()) return false; return _isCChar(c[0]);}
class PIP_EXPORT PICodeParser {
public:
PICodeParser();
enum Visibility {
Global,
Public,
Protected,
Private
};
enum Visibility {Global, Public, Protected, Private};
enum Attribute {
NoAttributes = 0x0,
Const = 0x01,
@@ -83,7 +73,7 @@ public:
is_type_ptr = false;
attributes = NoAttributes;
}
bool isBitfield() const { return bits > 0; }
bool isBitfield() const {return bits > 0;}
MetaMap meta;
PIString type;
PIString name;
@@ -112,26 +102,24 @@ public:
int size;
bool has_name;
Entity * parent_scope;
PIVector<Entity *> parents;
PIVector<Entity *> children;
PIVector<Entity * > parents;
PIVector<Entity * > children;
PIVector<Member> functions;
PIVector<Member> members;
PIVector<Typedef> typedefs;
};
struct PIP_EXPORT EnumeratorInfo {
EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {
name = n;
value = v;
meta = m;
}
EnumeratorInfo(const PIString & n = PIString(), int v = 0, const MetaMap & m = MetaMap()) {name = n; value = v; meta = m;}
MetaMap meta;
PIString name;
int value;
};
struct PIP_EXPORT Enum {
Enum(const PIString & n = PIString()) { name = n; }
Enum(const PIString & n = PIString()) {
name = n;
}
MetaMap meta;
PIString name;
PIVector<EnumeratorInfo> members;
@@ -139,24 +127,23 @@ public:
void parseFile(const PIString & file, bool follow_includes = true);
void parseFiles(const PIStringList & files, bool follow_includes = true);
void parseFileContent(PIString fc);
void includeDirectory(const PIString & dir) { includes << dir; }
void addDefine(const PIString & def_name, const PIString & def_value) { custom_defines << Define(def_name, def_value); }
void includeDirectory(const PIString & dir) {includes << dir;}
void addDefine(const PIString & def_name, const PIString & def_value) {custom_defines << Define(def_name, def_value);}
bool isEnum(const PIString & name);
Entity * findEntityByName(const PIString & en);
PIStringList parsedFiles() const { return PIStringList(proc_files.toVector()); }
PIString mainFile() const { return main_file; }
const PICodeParser::Entity * global() const { return &root_; }
PIStringList parsedFiles() const {return PIStringList(proc_files.toVector());}
PIString mainFile() const {return main_file;}
const PICodeParser::Entity * global() const {return &root_;}
int macrosSubstitutionMaxIterations() const { return macros_iter; }
void setMacrosSubstitutionMaxIterations(int value) { macros_iter = value; }
int macrosSubstitutionMaxIterations() const {return macros_iter;}
void setMacrosSubstitutionMaxIterations(int value) {macros_iter = value;}
PIVector<Define> defines, custom_defines;
PIVector<Macro> macros;
PIVector<Enum> enums;
PIVector<Typedef> typedefs;
PIVector<Entity *> entities;
PIVector<Entity * > entities;
private:
void clear();
@@ -194,6 +181,7 @@ private:
PIString cur_namespace;
PIMap<PIString, PIString> tmp_temp;
PIMap<PIString, MetaMap> tmp_meta;
};
#endif // PICODEPARSER_H

View File

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

View File

@@ -16,15 +16,13 @@
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 "pikbdlistener.h"
#include "piincludes_p.h"
#include "piliterals.h"
#include "pikbdlistener.h"
#ifndef WINDOWS
# include <termios.h>
#else
# include <wincon.h>
# include <wingdi.h>
# include <wincon.h>
#endif
/** \class PIKbdListener
@@ -49,82 +47,80 @@ PIKbdListener * PIKbdListener::_object = 0;
#ifndef WINDOWS
// unix
const PIKbdListener::EscSeq PIKbdListener::esc_seq[] = {
{"OA", PIKbdListener::UpArrow, 0, 0, 1},
{"OA", PIKbdListener::UpArrow, 4, 0, 0},
{"[1A", PIKbdListener::UpArrow, 0, 0, 0},
{"[A", PIKbdListener::UpArrow, 0, vt_all, 0},
{"OB", PIKbdListener::DownArrow, 0, 0, 1},
{"OB", PIKbdListener::DownArrow, 4, 0, 0},
{"[1B", PIKbdListener::DownArrow, 0, 0, 0},
{"[B", PIKbdListener::DownArrow, 0, vt_all, 0},
{"OC", PIKbdListener::RightArrow, 0, 0, 1},
{"OC", PIKbdListener::RightArrow, 4, 0, 0},
{"[1C", PIKbdListener::RightArrow, 0, 0, 0},
{"[C", PIKbdListener::RightArrow, 0, vt_all, 0},
{"OD", PIKbdListener::LeftArrow, 0, 0, 1},
{"OD", PIKbdListener::LeftArrow, 4, 0, 0},
{"[1D", PIKbdListener::LeftArrow, 0, 0, 0},
{"[D", PIKbdListener::LeftArrow, 0, vt_all, 0},
{"[H", PIKbdListener::Home, 0, vt_xterm, 0},
{"[1H", PIKbdListener::Home, 0, 0, 0},
{"OH", PIKbdListener::Home, 0, 0, 1},
{"[1~", PIKbdListener::Home, 0, vt_linux, 0},
{"[F", PIKbdListener::End, 0, vt_xterm, 0},
{"[1F", PIKbdListener::End, 0, 0, 0},
{"OF", PIKbdListener::End, 0, 0, 1},
{"[4~", PIKbdListener::End, 0, vt_linux, 0},
{"[2~", PIKbdListener::Insert, 0, vt_all, 0},
{"[3~", PIKbdListener::Delete, 0, vt_all, 0},
{"[5~", PIKbdListener::PageUp, 0, vt_all, 0},
{"[6~", PIKbdListener::PageDown, 0, vt_all, 0},
{"[Z", PIKbdListener::Tab, 1, vt_xterm, 0},
{"OP", PIKbdListener::F1, 0, vt_xterm, 0},
{"[[A", PIKbdListener::F1, 0, vt_linux, 0},
{"[11~", PIKbdListener::F1, 0, 0, 0},
{"[25~", PIKbdListener::F1, 1, vt_linux, 0},
{"OQ", PIKbdListener::F2, 0, vt_xterm, 0},
{"[[B", PIKbdListener::F2, 0, vt_linux, 0},
{"[12~", PIKbdListener::F2, 0, 0, 0},
{"[26~", PIKbdListener::F2, 1, vt_linux, 0},
{"OR", PIKbdListener::F3, 0, vt_xterm, 0},
{"[[C", PIKbdListener::F3, 0, vt_linux, 0},
{"[13~", PIKbdListener::F3, 0, 0, 0},
{"[28~", PIKbdListener::F3, 1, vt_linux, 0},
{"OS", PIKbdListener::F4, 0, vt_xterm, 0},
{"[[D", PIKbdListener::F4, 0, vt_linux, 0},
{"[14~", PIKbdListener::F4, 0, 0, 0},
{"[29~", PIKbdListener::F4, 1, vt_linux, 0},
{"[[E", PIKbdListener::F5, 0, vt_linux, 0},
{"OT", PIKbdListener::F5, 0, 0, 0},
{"[15~", PIKbdListener::F5, 0, vt_xterm, 0},
{"[31~", PIKbdListener::F5, 1, vt_linux, 0},
{"OU", PIKbdListener::F6, 0, 0, 0},
{"[17~", PIKbdListener::F6, 0, vt_all, 0},
{"[32~", PIKbdListener::F6, 1, vt_linux, 0},
{"OV", PIKbdListener::F7, 0, 0, 0},
{"[18~", PIKbdListener::F7, 0, vt_all, 0},
{"[33~", PIKbdListener::F7, 1, vt_linux, 0},
{"OW", PIKbdListener::F8, 0, 0, 0},
{"[19~", PIKbdListener::F8, 0, vt_all, 0},
{"[34~", PIKbdListener::F8, 1, vt_linux, 0},
{"OX", PIKbdListener::F9, 0, 0, 0},
{"[20~", PIKbdListener::F9, 0, vt_all, 0},
{"[35~", PIKbdListener::F9, 1, vt_linux, 0},
{"OY", PIKbdListener::F10, 0, 0, 0},
{"[21~", PIKbdListener::F10, 0, vt_all, 0},
{"[36~", PIKbdListener::F10, 1, vt_linux, 0},
{"OZ", PIKbdListener::F11, 0, 0, 0},
{"[23~", PIKbdListener::F11, 0, vt_all, 0},
{"O[", PIKbdListener::F12, 0, 0, 0},
{"[24~", PIKbdListener::F12, 0, vt_all, 0},
{"OA", PIKbdListener::UpArrow, 0, 0 , 1 },
{"OA", PIKbdListener::UpArrow, 4, 0 , 0 },
{"[1A", PIKbdListener::UpArrow, 0, 0 , 0 },
{"[A", PIKbdListener::UpArrow, 0, vt_all , 0 },
{"OB", PIKbdListener::DownArrow, 0, 0 , 1 },
{"OB", PIKbdListener::DownArrow, 4, 0 , 0 },
{"[1B", PIKbdListener::DownArrow, 0, 0 , 0 },
{"[B", PIKbdListener::DownArrow, 0, vt_all , 0 },
{"OC", PIKbdListener::RightArrow, 0, 0 , 1 },
{"OC", PIKbdListener::RightArrow, 4, 0 , 0 },
{"[1C", PIKbdListener::RightArrow, 0, 0 , 0 },
{"[C", PIKbdListener::RightArrow, 0, vt_all , 0 },
{"OD", PIKbdListener::LeftArrow, 0, 0 , 1 },
{"OD", PIKbdListener::LeftArrow, 4, 0 , 0 },
{"[1D", PIKbdListener::LeftArrow, 0, 0 , 0 },
{"[D", PIKbdListener::LeftArrow, 0, vt_all , 0 },
{"[H", PIKbdListener::Home, 0, vt_xterm , 0 },
{"[1H", PIKbdListener::Home, 0, 0 , 0 },
{"OH", PIKbdListener::Home, 0, 0 , 1 },
{"[1~", PIKbdListener::Home, 0, vt_linux , 0 },
{"[F", PIKbdListener::End, 0, vt_xterm , 0 },
{"[1F", PIKbdListener::End, 0, 0 , 0 },
{"OF", PIKbdListener::End, 0, 0 , 1 },
{"[4~", PIKbdListener::End, 0, vt_linux , 0 },
{"[2~", PIKbdListener::Insert, 0, vt_all , 0 },
{"[3~", PIKbdListener::Delete, 0, vt_all , 0 },
{"[5~", PIKbdListener::PageUp, 0, vt_all , 0 },
{"[6~", PIKbdListener::PageDown, 0, vt_all , 0 },
{"[Z", PIKbdListener::Tab, 1, vt_xterm , 0 },
{"OP", PIKbdListener::F1, 0, vt_xterm , 0 },
{"[[A", PIKbdListener::F1, 0, vt_linux , 0 },
{"[11~", PIKbdListener::F1, 0, 0 , 0 },
{"[25~", PIKbdListener::F1, 1, vt_linux , 0 },
{"OQ", PIKbdListener::F2, 0, vt_xterm , 0 },
{"[[B", PIKbdListener::F2, 0, vt_linux , 0 },
{"[12~", PIKbdListener::F2, 0, 0 , 0 },
{"[26~", PIKbdListener::F2, 1, vt_linux , 0 },
{"OR", PIKbdListener::F3, 0, vt_xterm , 0 },
{"[[C", PIKbdListener::F3, 0, vt_linux , 0 },
{"[13~", PIKbdListener::F3, 0, 0 , 0 },
{"[28~", PIKbdListener::F3, 1, vt_linux , 0 },
{"OS", PIKbdListener::F4, 0, vt_xterm , 0 },
{"[[D", PIKbdListener::F4, 0, vt_linux , 0 },
{"[14~", PIKbdListener::F4, 0, 0 , 0 },
{"[29~", PIKbdListener::F4, 1, vt_linux , 0 },
{"[[E", PIKbdListener::F5, 0, vt_linux , 0 },
{"OT", PIKbdListener::F5, 0, 0 , 0 },
{"[15~", PIKbdListener::F5, 0, vt_xterm , 0 },
{"[31~", PIKbdListener::F5, 1, vt_linux , 0 },
{"OU", PIKbdListener::F6, 0, 0 , 0 },
{"[17~", PIKbdListener::F6, 0, vt_all , 0 },
{"[32~", PIKbdListener::F6, 1, vt_linux , 0 },
{"OV", PIKbdListener::F7, 0, 0 , 0 },
{"[18~", PIKbdListener::F7, 0, vt_all , 0 },
{"[33~", PIKbdListener::F7, 1, vt_linux , 0 },
{"OW", PIKbdListener::F8, 0, 0 , 0 },
{"[19~", PIKbdListener::F8, 0, vt_all , 0 },
{"[34~", PIKbdListener::F8, 1, vt_linux , 0 },
{"OX", PIKbdListener::F9, 0, 0 , 0 },
{"[20~", PIKbdListener::F9, 0, vt_all , 0 },
{"[35~", PIKbdListener::F9, 1, vt_linux , 0 },
{"OY", PIKbdListener::F10, 0, 0 , 0 },
{"[21~", PIKbdListener::F10, 0, vt_all , 0 },
{"[36~", PIKbdListener::F10, 1, vt_linux , 0 },
{"OZ", PIKbdListener::F11, 0, 0 , 0 },
{"[23~", PIKbdListener::F11, 0, vt_all , 0 },
{"O[", PIKbdListener::F12, 0, 0 , 0 },
{"[24~", PIKbdListener::F12, 0, vt_all , 0 },
// End
{0, 0, 0, 0, 0},
};
void setupTerminal(bool on) {
printf("\e[?1000");
printf(on ? "h" : "l");
printf("\e[?1002");
printf(on ? "h" : "l");
printf("\e[?1000"); printf(on ? "h" : "l");
printf("\e[?1002"); printf(on ? "h" : "l");
fflush(0);
}
#endif
@@ -132,7 +128,7 @@ void setupTerminal(bool on) {
PRIVATE_DEFINITION_START(PIKbdListener)
#ifdef WINDOWS
void *hIn, *hOut;
void * hIn, * hOut;
DWORD smode, tmode;
CONSOLE_SCREEN_BUFFER_INFO sbi;
#else
@@ -148,7 +144,7 @@ PRIVATE_DEFINITION_END(PIKbdListener)
PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread() {
setName("keyboard_listener"_a);
setName("keyboard_listener");
_object = this;
#ifdef WINDOWS
PRIVATE->hIn = GetStdHandle(STD_INPUT_HANDLE);
@@ -167,8 +163,7 @@ PIKbdListener::PIKbdListener(KBFunc slot, void * _d, bool startNow): PIThread()
PIKbdListener::~PIKbdListener() {
stop();
if (!waitForFinish(100_ms)) terminate();
terminate();
end();
}
@@ -198,7 +193,7 @@ PIKbdListener::KeyModifiers getModifiers(DWORD v, bool * shift = 0) {
if (ctrl) ret |= PIKbdListener::Ctrl;
if (shi) ret |= PIKbdListener::Shift;
if (alt) ret |= PIKbdListener::Alt;
// if (meta) ret |= PIKbdListener::Meta;
//if (meta) ret |= PIKbdListener::Meta;
if (v & CAPSLOCK_ON) shi = !shi;
if (shift) *shift = shi;
return ret;
@@ -220,119 +215,42 @@ void PIKbdListener::readKeyboard() {
#ifdef WINDOWS
INPUT_RECORD ir;
ReadConsoleInput(PRIVATE->hIn, &ir, 1, &(PRIVATE->ret));
//piCout << ir.EventType;
switch (ir.EventType) {
case KEY_EVENT: {
KEY_EVENT_RECORD ker = ir.Event.KeyEvent;
if (ker.bKeyDown) {
bool shift = false;
ke.modifiers = getModifiers(ker.dwControlKeyState, &shift);
// piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar);
//piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar);
switch (ker.wVirtualKeyCode) {
case 8:
PRIVATE->ret = 1;
ke.key = Backspace;
break;
case 33:
PRIVATE->ret = 1;
ke.key = PageUp;
break;
case 34:
PRIVATE->ret = 1;
ke.key = PageDown;
break;
case 35:
PRIVATE->ret = 1;
ke.key = End;
break;
case 36:
PRIVATE->ret = 1;
ke.key = Home;
break;
case 37:
PRIVATE->ret = 1;
ke.key = LeftArrow;
break;
case 38:
PRIVATE->ret = 1;
ke.key = UpArrow;
break;
case 39:
PRIVATE->ret = 1;
ke.key = RightArrow;
break;
case 40:
PRIVATE->ret = 1;
ke.key = DownArrow;
break;
case 45:
PRIVATE->ret = 1;
ke.key = Insert;
break;
case 46:
PRIVATE->ret = 1;
ke.key = Delete;
break;
case 8: PRIVATE->ret = 1; ke.key = Backspace; break;
case 33: PRIVATE->ret = 1; ke.key = PageUp; break;
case 34: PRIVATE->ret = 1; ke.key = PageDown; break;
case 35: PRIVATE->ret = 1; ke.key = End; break;
case 36: PRIVATE->ret = 1; ke.key = Home; break;
case 37: PRIVATE->ret = 1; ke.key = LeftArrow; break;
case 38: PRIVATE->ret = 1; ke.key = UpArrow; break;
case 39: PRIVATE->ret = 1; ke.key = RightArrow; break;
case 40: PRIVATE->ret = 1; ke.key = DownArrow; break;
case 45: PRIVATE->ret = 1; ke.key = Insert; break;
case 46: PRIVATE->ret = 1; ke.key = Delete; break;
case '\r':
case '\n':
PRIVATE->ret = 1;
ke.key = Return;
break;
case ' ':
PRIVATE->ret = 1;
ke.key = Space;
break;
case '\t':
PRIVATE->ret = 1;
ke.key = Tab;
break;
case 112:
PRIVATE->ret = 1;
ke.key = F1;
break;
case 113:
PRIVATE->ret = 1;
ke.key = F2;
break;
case 114:
PRIVATE->ret = 1;
ke.key = F3;
break;
case 115:
PRIVATE->ret = 1;
ke.key = F4;
break;
case 116:
PRIVATE->ret = 1;
ke.key = F5;
break;
case 117:
PRIVATE->ret = 1;
ke.key = F6;
break;
case 118:
PRIVATE->ret = 1;
ke.key = F7;
break;
case 119:
PRIVATE->ret = 1;
ke.key = F8;
break;
case 120:
PRIVATE->ret = 1;
ke.key = F9;
break;
case 121:
PRIVATE->ret = 1;
ke.key = F10;
break;
case 122:
PRIVATE->ret = 1;
ke.key = F11;
break;
case 123:
PRIVATE->ret = 1;
ke.key = F12;
break;
case '\n': PRIVATE->ret = 1; ke.key = Return; break;
case ' ': PRIVATE->ret = 1; ke.key = Space; break;
case '\t': PRIVATE->ret = 1; ke.key = Tab; break;
case 112: PRIVATE->ret = 1; ke.key = F1; break;
case 113: PRIVATE->ret = 1; ke.key = F2; break;
case 114: PRIVATE->ret = 1; ke.key = F3; break;
case 115: PRIVATE->ret = 1; ke.key = F4; break;
case 116: PRIVATE->ret = 1; ke.key = F5; break;
case 117: PRIVATE->ret = 1; ke.key = F6; break;
case 118: PRIVATE->ret = 1; ke.key = F7; break;
case 119: PRIVATE->ret = 1; ke.key = F8; break;
case 120: PRIVATE->ret = 1; ke.key = F9; break;
case 121: PRIVATE->ret = 1; ke.key = F10; break;
case 122: PRIVATE->ret = 1; ke.key = F11; break;
case 123: PRIVATE->ret = 1; ke.key = F12; break;
default:
PRIVATE->ret = 1;
rc[0] = 1;
@@ -343,25 +261,20 @@ void PIKbdListener::readKeyboard() {
}
break;
}
if (ke.key == 0) {
piMSleep(10);
return;
if (ke.key == 0) {piMSleep(10); return;}
} else {piMSleep(10); return;}
}
} else {
piMSleep(10);
return;
}
} break;
break;
case MOUSE_EVENT: {
MOUSE_EVENT_RECORD mer = ir.Event.MouseEvent;
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
me.modifiers = getModifiers(mer.dwControlKeyState);
MouseButtons mb = getButtons(mer.dwButtonState);
if (mer.dwEventFlags & MOUSE_WHEELED) {
memcpy((void *)(&we), (const void *)(&me), sizeof(me));
memcpy((void*)(&we), (const void*)(&me), sizeof(me));
we.action = MouseWheel;
we.direction = short((mer.dwButtonState >> 8) & 0xFFFF) > 0;
// piCout << "wheel" << we.direction;
//piCout << "wheel" << we.direction;
wheelEvent(we, kbddata_);
break;
} else {
@@ -384,23 +297,24 @@ void PIKbdListener::readKeyboard() {
prev_p_me = me;
}
tm_dbl.reset();
} else if (mb < me.buttons)
me.action = MouseButtonRelease;
else {
if (mb != 0) piCoutObj << "WTF";
break;
}
else if (mb < me.buttons) me.action = MouseButtonRelease;
else {if (mb != 0) piCoutObj << "WTF"; break;}
}
me.buttons = mb;
if (piCompareBinary(&prev_me, &me, sizeof(me))) break;
memcpy((void *)(&prev_me), (const void *)(&me), sizeof(me));
// PIString _s[] = {"press", "release", "dbl click", "move"};
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
if (piCompareBinary(&prev_me, &me, sizeof(me)))
break;
memcpy((void*)(&prev_me), (const void*)(&me), sizeof(me));
//PIString _s[] = {"press", "release", "dbl click", "move"};
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_);
break;
}
} break;
default: piMSleep(10); return;
}
break;
default:
piMSleep(10);
return;
}
#else
tcsetattr(0, TCSANOW, &PRIVATE->tterm);
@@ -413,14 +327,8 @@ void PIKbdListener::readKeyboard() {
for (int i = 0; i < PRIVATE->ret; ++i)
std::cout << "'" << (char)(rc[i]) << "' " << (int)(uchar)(rc[i]);
std::cout << std::endl;*/
if (rc[0] == 0) {
piMSleep(10);
return;
}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {
piMSleep(10);
return;
}
if (rc[0] == 0) {piMSleep(10); return;}
if (PRIVATE->ret < 0 || PRIVATE->ret > 7) {piMSleep(10); return;}
if (PRIVATE->ret == 1) {
if (rc[0] == 8)
ke.key = Backspace;
@@ -437,10 +345,9 @@ void PIKbdListener::readKeyboard() {
if (PRIVATE->ret == 2) {
mod = 2;
ke.key = PIChar::fromConsole(rc[1]).unicode16Code();
} else { // escape-seq
} else {// escape-seq
if (rc[1] == '\e') { // search for Alt
for (int i = 1; i < 7; ++i)
rc[i] = rc[i + 1];
for (int i = 1; i < 7; ++i) rc[i] = rc[i + 1];
mod = 2;
PRIVATE->ret--;
}
@@ -451,10 +358,10 @@ void PIKbdListener::readKeyboard() {
me.y = uchar(rc[5] - '!');
int b = rc[3] & 0x7, a = rc[3] & 0x60;
if (a == 0x60) {
memcpy((void *)(&we), (const void *)(&me), sizeof(me));
memcpy((void*)(&we), (const void*)(&me), sizeof(me));
we.action = MouseWheel;
we.direction = (b == 0);
// piCout << "wheel" << we.direction;
//piCout << "wheel" << we.direction;
wheelEvent(we, kbddata_);
} else {
switch (b) {
@@ -478,19 +385,18 @@ void PIKbdListener::readKeyboard() {
}
}
if (a == 0x40) me.action = MouseMove;
// PIString _s[] = {"press", "release", "dbl click", "move"};
// piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
//PIString _s[] = {"press", "release", "dbl click", "move"};
//piCoutObj << _s[me.action] << me.buttons << ":" << me.x << me.y;
mouseEvent(me, kbddata_);
}
// piCout << me.x << me.y << PICoutManipulators::Hex << b << a;
//piCout << me.x << me.y << PICoutManipulators::Hex << b << a;
}
return;
} else {
for (int i = 2; i < 7; ++i) // search for modifier
if (rc[i] == ';') {
mod |= rc[i + 1] - '0' - 1;
for (int j = i; j < 6; ++j)
rc[j] = rc[j + 2];
for (int j = i; j < 6; ++j) rc[j] = rc[j + 2];
rc[6] = rc[7] = 0;
PRIVATE->ret -= 2;
break;
@@ -500,15 +406,14 @@ void PIKbdListener::readKeyboard() {
if (PRIVATE->ret >= 3 && rc[1] == 'O') { // search for modifier (F1-F4)
if (rc[2] >= '1' && rc[2] <= '8') {
mod |= rc[2] - '0' - 1;
for (int j = 2; j < 6; ++j)
rc[j] = rc[j + 1];
for (int j = 2; j < 6; ++j) rc[j] = rc[j + 1];
rc[7] = 0;
PRIVATE->ret--;
}
}
for (int i = 0;; ++i) {
for (int i = 0; ; ++i) {
if (!esc_seq[i].seq) break;
// piCout << "search" << rc[1] << esc_seq[i].seq;
//piCout << "search" << rc[1] << esc_seq[i].seq;
if (strcmp(esc_seq[i].seq, &(rc[1])) == 0) {
ke.key = esc_seq[i].key;
mod |= esc_seq[i].mod;
@@ -520,16 +425,18 @@ void PIKbdListener::readKeyboard() {
if (mod & 0x1) ke.modifiers |= Shift;
if (mod & 0x2) ke.modifiers |= Alt;
if (mod & 0x4) ke.modifiers |= Ctrl;
// if (mod & 0x8) ke.modifiers |= Meta;
//if (mod & 0x8) ke.modifiers |= Meta;
}
/*cout << "wo mods (" << mod << ")\n";
for (int i = 0; i < PRIVATE->ret; ++i)
cout << "'" << (char)(rc[i]) << "' ";
cout << endl;*/
}
if (ke.key == 0 && PRIVATE->ret > 1) ke.key = PIChar::fromSystem(rc).unicode16Code();
if (ke.key == 0 && PRIVATE->ret > 1)
ke.key = PIChar(rc).unicode16Code();
#endif
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1) ke.key = Return;
if ((rc[0] == '\n' || rc[0] == '\r') && PRIVATE->ret == 1)
ke.key = Return;
if (exit_enabled && ke.key == exit_key) {
PIKbdListener::exiting = true;
return;
@@ -541,13 +448,8 @@ void PIKbdListener::readKeyboard() {
}
void PIKbdListener::stop() {
PIThread::stop();
}
void PIKbdListener::end() {
// cout << "list end" << endl;
//cout << "list end" << endl;
#ifdef WINDOWS
SetConsoleMode(PRIVATE->hIn, PRIVATE->smode);
#else

View File

@@ -27,20 +27,17 @@
#define PIKBDLISTENER_H
#include "pithread.h"
#include "pitime.h"
#define WAIT_FOR_EXIT \
while (!PIKbdListener::exiting) \
piMSleep(PIP_MIN_MSLEEP * 5); \
if (PIKbdListener::instance()) PIKbdListener::instance()->stopAndWait();
#define WAIT_FOR_EXIT while (!PIKbdListener::exiting) piMSleep(PIP_MIN_MSLEEP*5); // TODO: rewrite with condvar
class PIP_EXPORT PIKbdListener: public PIThread {
PIOBJECT_SUBCLASS(PIKbdListener, PIThread);
class PIP_EXPORT PIKbdListener: public PIThread
{
PIOBJECT_SUBCLASS(PIKbdListener, PIThread)
friend class PIConsole;
friend class PITerminal;
public:
//! Special keyboard keys
enum SpecialKey {
Tab /** Tab key */ = 0x09,
@@ -77,17 +74,14 @@ public:
Ctrl /** Control key */ = 0x1,
Shift /** Shift key */ = 0x2,
Alt /** Alt key */ = 0x4
// Meta /** Meta (windows) key */ = 0x8
//Meta /** Meta (windows) key */ = 0x8
};
typedef PIFlags<KeyModifier> KeyModifiers;
//! This struct contains information about pressed keyboard key
struct PIP_EXPORT KeyEvent {
KeyEvent(int k = 0, KeyModifiers m = 0) {
key = k;
modifiers = m;
}
KeyEvent(int k = 0, KeyModifiers m = 0) {key = k; modifiers = m;}
//! Pressed key. It can be simple \b char or special key (see PIKbdListener::SpecialKey)
int key;
@@ -116,12 +110,7 @@ public:
//! This struct contains information about mouse action
struct PIP_EXPORT MouseEvent {
MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {
x = y = 0;
action = a;
buttons = b;
modifiers = m;
}
MouseEvent(MouseAction a = MouseButtonPress, MouseButtons b = 0, KeyModifiers m = 0) {x = y = 0; action = a; buttons = b; modifiers = m;}
//! Event X coordinate in view-space, from 0
int x;
@@ -141,7 +130,7 @@ public:
//! This struct contains information about mouse wheel action
struct PIP_EXPORT WheelEvent: public MouseEvent {
WheelEvent(): MouseEvent() { direction = false; }
WheelEvent(): MouseEvent() {direction = false;}
//! Wheel direction, /b true - up, /b fasle - down
bool direction;
@@ -156,50 +145,43 @@ public:
//! Returns custom data
void * data() { return kbddata_; }
void * data() {return kbddata_;}
//! Set custom data to "_data"
void setData(void * _data) { kbddata_ = _data; }
void setData(void * _data) {kbddata_ = _data;}
//! Set external function to "slot"
void setSlot(KBFunc slot) { ret_func = slot; }
void setSlot(KBFunc slot) {ret_func = slot;}
//! Set external function to "slot"
void setSlot(std::function<void(KeyEvent)> slot) {
ret_func = [slot](KeyEvent e, void *) { slot(e); };
}
void setSlot(std::function<void(KeyEvent)> slot) {ret_func = [slot](KeyEvent e, void *){slot(e);};}
//! Returns if exit key if awaiting
bool exitCaptured() const { return exit_enabled; }
bool exitCaptured() const {return exit_enabled;}
//! Returns exit key, default 'Q'
int exitKey() const { return exit_key; }
int exitKey() const {return exit_key;}
double doubleClickInterval() const { return dbl_interval; }
void setDoubleClickInterval(double v) { dbl_interval = v; }
double doubleClickInterval() const {return dbl_interval;}
void setDoubleClickInterval(double v) {dbl_interval = v;}
void readKeyboard();
void stop();
//! Returns if keyboard listening is active (not running!)
bool isActive() { return is_active; }
bool isActive() {return is_active;}
EVENT_HANDLER(void, enableExitCapture) { enableExitCapture('Q'); }
EVENT_HANDLER1(void, enableExitCapture, int, key) {
exit_enabled = true;
exit_key = key;
}
EVENT_HANDLER(void, disableExitCapture) { exit_enabled = false; }
EVENT_HANDLER(void, setActive) { setActive(true); }
EVENT_HANDLER( void, enableExitCapture) {enableExitCapture('Q');}
EVENT_HANDLER1(void, enableExitCapture, int, key) {exit_enabled = true; exit_key = key;}
EVENT_HANDLER(void, disableExitCapture) {exit_enabled = false;}
EVENT_HANDLER(void, setActive) {setActive(true);}
EVENT_HANDLER1(void, setActive, bool, yes);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data);
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void *, data);
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void *, data);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(mouseEvent, PIKbdListener::MouseEvent, mouse, void * , data)
EVENT2(wheelEvent, PIKbdListener::WheelEvent, wheel, void * , data)
//! \handlers
//! \{
//! \handlers
//! \{
//! \fn void enableExitCapture(int key = 'Q')
//! \brief Enable exit key "key" awaiting
@@ -210,22 +192,22 @@ public:
//! \fn void setActive(bool yes = true)
//! \brief Set keyboard listening is active or not
//! \}
//! \events
//! \{
//! \}
//! \events
//! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! \brief Raise on key "key" pressed, "data" is custom data
//! \}
//! \}
static bool exiting;
static PIKbdListener * instance() { return _object; }
static PIKbdListener * instance() {return _object;}
private:
void begin() override;
void run() override { readKeyboard(); }
void end() override;
void begin();
void run() {readKeyboard();}
void end();
#ifndef WINDOWS
struct PIP_EXPORT EscSeq {
@@ -261,42 +243,17 @@ private:
MouseEvent me, prev_me, prev_p_me;
WheelEvent we;
static PIKbdListener * _object;
};
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::MouseEvent) {
s << v.x << v.y << v.action << v.buttons << v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::MouseEvent) {
s >> v.x >> v.y >> v.action >> v.buttons >> v.modifiers;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Store operator
//! \~russian Оператор сохранения
BINARY_STREAM_WRITE(PIKbdListener::WheelEvent) {
s << (*(PIKbdListener::MouseEvent *)&v) << v.direction;
return s;
}
//! \relatesalso PIBinaryStream
//! \~english Restore operator
//! \~russian Оператор извлечения
BINARY_STREAM_READ(PIKbdListener::WheelEvent) {
s >> (*(PIKbdListener::MouseEvent *)&v) >> v.direction;
return s;
}
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << v.modifiers; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::MouseEvent & v) {s << v.x << v.y << (int)v.action << v.buttons << v.modifiers; return s;}
inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::WheelEvent & v) {s << (*(PIKbdListener::MouseEvent*)&v) << (uchar)v.direction; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {s >> v.key >> v.modifiers; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::MouseEvent & v) {int a(0); s >> v.x >> v.y >> a >> v.buttons >> v.modifiers; v.action = (PIKbdListener::MouseAction)a; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::WheelEvent & v) {uchar d(0); s >> (*(PIKbdListener::MouseEvent*)&v) >> d; v.direction = d; return s;}
REGISTER_PIVARIANTSIMPLE(PIKbdListener::KeyEvent)
REGISTER_PIVARIANTSIMPLE(PIKbdListener::MouseEvent)

View File

@@ -27,61 +27,60 @@
#define PISCREEN_H
#include "pip_console_export.h"
#include "piscreendrawer.h"
#include "piscreentile.h"
#include "piscreendrawer.h"
class PIP_CONSOLE_EXPORT PIScreen
: public PIThread
, public PIScreenTypes::PIScreenBase {
PIOBJECT_SUBCLASS(PIScreen, PIThread);
class PIP_CONSOLE_EXPORT PIScreen: public PIThread, public PIScreenTypes::PIScreenBase
{
PIOBJECT_SUBCLASS(PIScreen, PIThread)
class SystemConsole;
public:
//! Constructs %PIScreen with key handler "slot" and if "startNow" start it
PIScreen(bool startNow = true, PIKbdListener::KBFunc slot = 0);
~PIScreen();
//! Directly call function from \a PIKbdListener
void enableExitCapture(int key = 'Q') { listener->enableExitCapture(key); }
void enableExitCapture(int key = 'Q') {listener->enableExitCapture(key);}
//! Directly call function from \a PIKbdListener
void disableExitCapture() { listener->disableExitCapture(); }
void disableExitCapture() {listener->disableExitCapture();}
//! Directly call function from \a PIKbdListener
bool exitCaptured() const { return listener->exitCaptured(); }
bool exitCaptured() const {return listener->exitCaptured();}
//! Directly call function from \a PIKbdListener
int exitKey() const { return listener->exitKey(); }
int exitKey() const {return listener->exitKey();}
int windowWidth() const { return console.width; }
int windowHeight() const { return console.height; }
int windowWidth() const {return console.width;}
int windowHeight() const {return console.height;}
bool isMouseEnabled() const { return mouse_; }
bool isMouseEnabled() const {return mouse_;}
void setMouseEnabled(bool on);
PIScreenTile * rootTile() { return &root; }
PIScreenTile * rootTile() {return &root;}
PIScreenTile * tileByName(const PIString & name);
void setDialogTile(PIScreenTile * t);
PIScreenTile * dialogTile() const { return tile_dialog; }
PIScreenTile * dialogTile() const {return tile_dialog;}
PIScreenDrawer * drawer() { return &drawer_; }
void clear() { drawer_.clear(); }
void resize(int w, int h) { console.resize(w, h); }
PIScreenDrawer * drawer() {return &drawer_;}
void clear() {drawer_.clear();}
void resize(int w, int h) {console.resize(w, h);}
EVENT_HANDLER0(void, waitForFinish);
EVENT_HANDLER0(void, start) { start(false); }
EVENT_HANDLER1(void, start, bool, wait);
EVENT_HANDLER0(void, stop) { stop(false); }
EVENT_HANDLER0(void, start) {start(false);}
EVENT_HANDLER1(void, start, bool, wait) {PIThread::start(40); if (wait) waitForFinish();}
EVENT_HANDLER0(void, stop) {stop(false);}
EVENT_HANDLER1(void, stop, bool, clear);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void *, data);
EVENT2(tileEvent, PIScreenTile *, tile, PIScreenTypes::TileEvent, e);
EVENT2(keyPressed, PIKbdListener::KeyEvent, key, void * , data)
EVENT2(tileEvent, PIScreenTile * , tile, PIScreenTypes::TileEvent, e)
//! \handlers
//! \{
//! \handlers
//! \{
//! \fn void waitForFinish()
//! \brief block until finished (exit key will be pressed)
@@ -92,9 +91,9 @@ public:
//! \fn void stop(bool clear = false)
//! \brief Stop console output and if "clear" clear the screen
//! \}
//! \events
//! \{
//! \}
//! \events
//! \{
//! \fn void keyPressed(PIKbdListener::KeyEvent key, void * data)
//! \brief Raise on key "key" pressed, "data" is pointer to %PIConsole object
@@ -102,7 +101,7 @@ public:
//! \fn void tileEvent(PIScreenTile * tile, PIScreenTypes::TileEvent e)
//! \brief Raise on some event "e" from tile "tile"
//! \}
//! \}
private:
class PIP_CONSOLE_EXPORT SystemConsole {
@@ -132,23 +131,23 @@ private:
PRIVATE_DECLARATION(PIP_CONSOLE_EXPORT)
int width, height, pwidth, pheight;
int mouse_x, mouse_y;
PIVector<PIVector<PIScreenTypes::Cell>> cells, pcells;
PIVector<PIVector<PIScreenTypes::Cell> > cells, pcells;
};
void begin() override;
void run() override;
void end() override;
void begin();
void run();
void end();
void key_event(PIKbdListener::KeyEvent key);
EVENT_HANDLER1(void, mouse_event, PIKbdListener::MouseEvent, me);
EVENT_HANDLER1(void, wheel_event, PIKbdListener::WheelEvent, we);
static void key_eventS(PIKbdListener::KeyEvent key, void * t) { ((PIScreen *)t)->key_event(key); }
PIVector<PIScreenTile *> tiles() { return root.children(); }
PIVector<PIScreenTile *> prepareMouse(PIKbdListener::MouseEvent * e);
PIVector<PIScreenTile *> tilesUnderMouse(int x, int y);
static void key_eventS(PIKbdListener::KeyEvent key, void * t) {((PIScreen*)t)->key_event(key);}
PIVector<PIScreenTile*> tiles() {return root.children();}
PIVector<PIScreenTile*> prepareMouse(PIKbdListener::MouseEvent * e);
PIVector<PIScreenTile*> tilesUnderMouse(int x, int y);
bool nextFocus(PIScreenTile * rt, PIKbdListener::KeyEvent key = PIKbdListener::KeyEvent());
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e) override;
void tileRemovedInternal(PIScreenTile * t) override;
void tileSetFocusInternal(PIScreenTile * t) override;
void tileEventInternal(PIScreenTile * t, PIScreenTypes::TileEvent e);
void tileRemovedInternal(PIScreenTile * t);
void tileSetFocusInternal(PIScreenTile * t);
bool mouse_;
SystemConsole console;
@@ -156,7 +155,8 @@ private:
PIKbdListener * listener;
PIKbdListener::KBFunc ret_func;
PIScreenTile root;
PIScreenTile *tile_focus, *tile_dialog;
PIScreenTile * tile_focus, * tile_dialog;
};

View File

@@ -35,15 +35,10 @@
class PIP_CONSOLE_EXPORT TileVars: public PIScreenTile {
public:
TileVars(const PIString & n = PIString());
protected:
struct PIP_CONSOLE_EXPORT Variable {
Variable() {
nx = ny = type = offset = bitFrom = bitCount = size = 0;
format = PIScreenTypes::CellFormat();
ptr = 0;
}
bool isEmpty() const { return (ptr == 0); }
Variable() {nx = ny = type = offset = bitFrom = bitCount = size = 0; format = PIScreenTypes::CellFormat(); ptr = 0;}
bool isEmpty() const {return (ptr == 0);}
PIString name;
PIScreenTypes::CellFormat format;
int nx;
@@ -69,12 +64,14 @@ protected:
};
PIVector<Variable> variables;
PIScreenTypes::Alignment alignment;
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
};
class PIP_CONSOLE_EXPORT PIScreenConsoleTile: public PIScreenTile {
class PIP_CONSOLE_EXPORT PIScreenConsoleTile : public PIScreenTile
{
public:
PIScreenConsoleTile();
};

View File

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

View File

@@ -26,44 +26,36 @@
#ifndef PISCREENTILE_H
#define PISCREENTILE_H
#include "pikbdlistener.h"
#include "pip_console_export.h"
#include "piscreentypes.h"
#include "pikbdlistener.h"
class PIScreenDrawer;
class PIP_CONSOLE_EXPORT PIScreenTile: public PIObject {
friend class PIScreen;
PIOBJECT_SUBCLASS(PIScreenTile, PIObject);
PIOBJECT_SUBCLASS(PIScreenTile, PIObject)
public:
PIScreenTile(const PIString & n = PIString(),
PIScreenTypes::Direction d = PIScreenTypes::Vertical,
PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
PIScreenTile(const PIString & n = PIString(), PIScreenTypes::Direction d = PIScreenTypes::Vertical, PIScreenTypes::SizePolicy p = PIScreenTypes::Preferred);
virtual ~PIScreenTile();
void addTile(PIScreenTile * t);
void takeTile(PIScreenTile * t);
void removeTile(PIScreenTile * t);
PIScreenTile * parentTile() const { return parent; }
PIVector<PIScreenTile *> children(bool only_visible = false);
PIScreenTile * parentTile() const {return parent;}
PIVector<PIScreenTile * > children(bool only_visible = false);
PIScreenTile * childUnderMouse(int x, int y);
void show() { visible = true; }
void hide() { visible = false; }
void show() {visible = true;}
void hide() {visible = false;}
void setFocus();
bool hasFocus() const { return has_focus; }
void setMargins(int m) { marginLeft = marginRight = marginTop = marginBottom = m; }
void setMargins(int l, int r, int t, int b) {
marginLeft = l;
marginRight = r;
marginTop = t;
marginBottom = b;
}
bool hasFocus() const {return has_focus;}
void setMargins(int m) {marginLeft = marginRight = marginTop = marginBottom = m;}
void setMargins(int l, int r, int t, int b) {marginLeft = l; marginRight = r; marginTop = t; marginBottom = b;}
int x() const { return x_; }
int y() const { return y_; }
int width() const { return width_; }
int height() const { return height_; }
int x() const {return x_;}
int y() const {return y_;}
int width() const {return width_;}
int height() const {return height_;}
PIScreenTypes::Direction direction;
PIScreenTypes::SizePolicy size_policy;
@@ -77,6 +69,7 @@ public:
bool visible;
protected:
//! Returns desired tile size in "w" and "h"
virtual void sizeHint(int & w, int & h) const;
@@ -87,22 +80,22 @@ protected:
virtual void drawEvent(PIScreenDrawer * d) {}
//! Return "true" if you process key
virtual bool keyEvent(PIKbdListener::KeyEvent key) { return false; }
virtual bool keyEvent(PIKbdListener::KeyEvent key) {return false;}
//! Return "true" if you process event
virtual bool mouseEvent(PIKbdListener::MouseEvent me) { return false; }
virtual bool mouseEvent(PIKbdListener::MouseEvent me) {return false;}
//! Return "true" if you process wheel
virtual bool wheelEvent(PIKbdListener::WheelEvent we) { return false; }
virtual bool wheelEvent(PIKbdListener::WheelEvent we) {return false;}
void raiseEvent(PIScreenTypes::TileEvent e);
void setScreen(PIScreenTypes::PIScreenBase * s);
void deleteChildren();
void drawEventInternal(PIScreenDrawer * d);
void layout();
bool needLayout() { return size_policy != PIScreenTypes::Ignore; }
bool needLayout() {return size_policy != PIScreenTypes::Ignore;}
PIVector<PIScreenTile *> tiles;
PIVector<PIScreenTile * > tiles;
PIScreenTile * parent;
PIScreenTypes::PIScreenBase * screen;
int x_, y_, width_, height_;
@@ -110,6 +103,7 @@ protected:
private:
int pw, ph;
};

View File

@@ -31,8 +31,7 @@
class PIP_CONSOLE_EXPORT TileSimple: public PIScreenTile {
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile);
PIOBJECT_SUBCLASS(TileSimple, PIScreenTile)
public:
typedef PIPair<PIString, PIScreenTypes::CellFormat> Row;
TileSimple(const PIString & n = PIString());
@@ -40,43 +39,39 @@ public:
virtual ~TileSimple() {}
PIVector<Row> content;
PIScreenTypes::Alignment alignment;
protected:
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
};
class TileList;
class PIP_CONSOLE_EXPORT TileScrollBar: public PIScreenTile {
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile);
PIOBJECT_SUBCLASS(TileScrollBar, PIScreenTile)
friend class TileList;
public:
TileScrollBar(const PIString & n = PIString());
virtual ~TileScrollBar() {}
void setMinimum(int v);
void setMaximum(int v);
void setValue(int v);
int minimum() const { return minimum_; }
int maximum() const { return maximum_; }
int value() const { return value_; }
int minimum() const {return minimum_;}
int maximum() const {return maximum_;}
int value() const {return value_;}
int thickness;
protected:
void _check();
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool mouseEvent(PIKbdListener::MouseEvent me);
int minimum_, maximum_, value_;
PIChar line_char;
};
class PIP_CONSOLE_EXPORT TileList: public PIScreenTile {
PIOBJECT_SUBCLASS(TileList, PIScreenTile);
PIOBJECT_SUBCLASS(TileList, PIScreenTile)
public:
enum SelectionMode {
NoSelection,
@@ -97,22 +92,20 @@ public:
SelectionMode selection_mode;
PISet<int> selected;
int lhei, cur, offset;
protected:
void sizeHint(int & w, int & h) const override;
void resizeEvent(int w, int h) override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
bool wheelEvent(PIKbdListener::WheelEvent we) override;
void sizeHint(int & w, int & h) const;
void resizeEvent(int w, int h);
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
bool wheelEvent(PIKbdListener::WheelEvent we);
TileScrollBar * scroll;
bool mouse_sel;
};
class PIP_CONSOLE_EXPORT TileButton: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButton, PIScreenTile);
PIOBJECT_SUBCLASS(TileButton, PIScreenTile)
public:
TileButton(const PIString & n = PIString());
virtual ~TileButton() {}
@@ -121,18 +114,18 @@ public:
};
PIScreenTypes::CellFormat format;
PIString text;
protected:
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
};
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile);
class PIP_CONSOLE_EXPORT TileButtons: public PIScreenTile {
PIOBJECT_SUBCLASS(TileButtons, PIScreenTile)
public:
TileButtons(const PIString & n = PIString());
virtual ~TileButtons() {}
@@ -143,23 +136,21 @@ public:
PIScreenTypes::Alignment alignment;
PIVector<Button> content;
int cur;
protected:
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
struct Rect {
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0), y0(_y0), x1(_x1), y1(_y1) {}
int x0, y0, x1, y1;
Rect(int _x0 = 0, int _y0 = 0, int _x1 = 0, int _y1 = 0): x0(_x0),y0(_y0),x1(_x1),y1(_y1) {}
int x0,y0,x1,y1;
};
PIVector<Rect> btn_rects;
};
class PIP_CONSOLE_EXPORT TileCheck: public PIScreenTile {
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile);
PIOBJECT_SUBCLASS(TileCheck, PIScreenTile)
public:
TileCheck(const PIString & n = PIString());
virtual ~TileCheck() {}
@@ -169,18 +160,16 @@ public:
PIScreenTypes::CellFormat format;
PIString text;
bool toggled;
protected:
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
bool mouseEvent(PIKbdListener::MouseEvent me) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
bool mouseEvent(PIKbdListener::MouseEvent me);
};
class PIP_CONSOLE_EXPORT TileProgress: public PIScreenTile {
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile);
PIOBJECT_SUBCLASS(TileProgress, PIScreenTile)
public:
TileProgress(const PIString & n = PIString());
virtual ~TileProgress() {}
@@ -189,42 +178,37 @@ public:
PIString suffix;
double maximum;
double value;
protected:
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
};
class PIP_CONSOLE_EXPORT TilePICout: public TileList {
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile);
PIOBJECT_SUBCLASS(TilePICout, PIScreenTile)
public:
TilePICout(const PIString & n = PIString());
virtual ~TilePICout() {}
PIScreenTypes::CellFormat format;
int max_lines;
protected:
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
};
class PIP_CONSOLE_EXPORT TileInput: public PIScreenTile {
PIOBJECT_SUBCLASS(TileInput, PIScreenTile);
PIOBJECT_SUBCLASS(TileInput, PIScreenTile)
public:
TileInput(const PIString & n = PIString());
virtual ~TileInput() {}
PIScreenTypes::CellFormat format;
PIString text;
int max_length;
protected:
void sizeHint(int & w, int & h) const override;
void drawEvent(PIScreenDrawer * d) override;
bool keyEvent(PIKbdListener::KeyEvent key) override;
void sizeHint(int & w, int & h) const;
void drawEvent(PIScreenDrawer * d);
bool keyEvent(PIKbdListener::KeyEvent key);
void reserCursor();
int cur, offset;
bool inv;

View File

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

View File

@@ -26,39 +26,39 @@
#ifndef PITERMINAL_H
#define PITERMINAL_H
#include "pikbdlistener.h"
#include "pip_console_export.h"
#include "pikbdlistener.h"
#include "piscreentypes.h"
class PIP_CONSOLE_EXPORT PITerminal: public PIThread {
PIOBJECT_SUBCLASS(PITerminal, PIThread);
class PIP_CONSOLE_EXPORT PITerminal: public PIThread
{
PIOBJECT_SUBCLASS(PITerminal, PIThread)
public:
//! Constructs %PITerminal
PITerminal();
~PITerminal();
int columns() const { return size_x; }
int rows() const { return size_y; }
int columns() const {return size_x;}
int rows() const {return size_y;}
bool resize(int cols, int rows);
void write(const PIByteArray & d);
void write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m);
void write(PIKbdListener::KeyEvent ke);
PIVector<PIVector<PIScreenTypes::Cell>> content();
PIVector<PIVector<PIScreenTypes::Cell> > content();
static bool isSpecialKey(int k);
bool initialize();
void destroy();
private:
void initPrivate();
void readConsole();
void getCursor(int & x, int & y);
uchar invertColor(uchar c);
void run() override;
void run();
#ifndef WINDOWS
void parseInput(const PIString & s);
bool isCompleteEscSeq(const PIString & es);
@@ -72,7 +72,8 @@ private:
int size_x, size_y, cursor_x, cursor_y;
bool cursor_blink, cursor_visible;
PITimeMeasurer cursor_tm;
PIVector<PIVector<PIScreenTypes::Cell>> cells;
PIVector<PIVector<PIScreenTypes::Cell> > cells;
};

View File

@@ -20,16 +20,15 @@
#include "picontainers.h"
const size_t minAlloc = 64;
const ssize_t minAlloc = 64;
size_t _PIContainerConstantsBase::calcMinCountPoT(size_t szof) {
size_t ret = 0;
size_t elc = 1;
ssize_t _PIContainerConstantsBase::calcMinCountPoT(ssize_t szof) {
ssize_t ret = 0, elc = 1;
while (elc * szof < minAlloc) {
elc *= 2;
++ret;
}
// printf("calcMinCount sizeof = %d, min_count = %d, pot = %d\n", szof, elc, ret);
//printf("calcMinCount sizeof = %d, min_count = %d, pot = %d\n", szof, elc, ret);
return ret;
}

View File

@@ -41,24 +41,23 @@
#else
# include <malloc.h>
#endif
#include <initializer_list>
#include <type_traits>
#include <string.h>
#include <new>
#include <algorithm>
#include <functional>
#include <initializer_list>
#include <new>
#include <string.h>
#include <type_traits>
template<typename C>
template <typename C>
class _PIReverseWrapper {
public:
_PIReverseWrapper(C & c): c_(c) {}
_PIReverseWrapper(const C & c): c_(const_cast<C &>(c)) {}
typename C::reverse_iterator begin() { return c_.rbegin(); }
typename C::reverse_iterator end() { return c_.rend(); }
typename C::const_reverse_iterator begin() const { return c_.rbegin(); }
typename C::const_reverse_iterator end() const { return c_.rend(); }
_PIReverseWrapper(const C & c): c_(const_cast<C&>(c)) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
typename C::const_reverse_iterator begin() const {return c_.rbegin();}
typename C::const_reverse_iterator end() const {return c_.rend(); }
private:
C & c_;
};
@@ -66,30 +65,21 @@ private:
class PIP_EXPORT _PIContainerConstantsBase {
public:
static size_t calcMinCountPoT(size_t szof);
static ssize_t calcMinCountPoT(ssize_t szof);
};
template<typename T>
class _PIContainerConstants {
public:
static size_t minCountPoT() {
static const size_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T));
return ret;
}
static ssize_t minCountPoT() {static ssize_t ret = _PIContainerConstantsBase::calcMinCountPoT(sizeof(T)); return ret;}
};
//! \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);
}
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);}
//! \brief
@@ -98,7 +88,7 @@ _PIReverseWrapper<C> PIReverseWrap(const C & c) {
//! \~\param c
//! \~english Iteration times in loop
//! \~russian Количество итераций цикла
#define piForTimes(c) for (int _i##c = 0; _i##c < c; ++_i##c)
#define piForTimes(c) for(int _i##c = 0; _i##c < c; ++_i##c)
//! \brief
@@ -130,7 +120,7 @@ _PIReverseWrapper<C> PIReverseWrap(const C & c) {
//! // 4
//! \endcode
//! \sa \a piForeachC, \a piForeachR, \a piForeachRC
#define piForeach(i, c) for (i: c)
#define piForeach(i, c) for(i : c)
//! \brief
//! \~english Macro for iterate any container
@@ -146,7 +136,7 @@ _PIReverseWrapper<C> PIReverseWrap(const C & c) {
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
//! Перебор осуществляется в прямом порядке.
//! \~ \sa \a piForeach, \a piForeachR, \a piForeachRC
#define piForeachC(i, c) for (const i: c)
#define piForeachC(i, c) for(const i : c)
//! \brief
//! \~english Macro for iterate any container
@@ -162,7 +152,7 @@ _PIReverseWrapper<C> PIReverseWrap(const C & c) {
//! \~russian Перебор всех элементов контейнера с доступом на чтение и запись.
//! Перебор осуществляется в обратном порядке.
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachRC
#define piForeachR(i, c) for (i: PIReverseWrap(c))
#define piForeachR(i, c) for(i : PIReverseWrap(c))
//! \brief
//! \~english Macro for iterate any container
@@ -178,7 +168,7 @@ _PIReverseWrapper<C> PIReverseWrap(const C & c) {
//! \~russian Перебор всех элементов контейнера с доступом только на чтение.
//! Перебор осуществляется в обратном порядке. Также можно писать **piForeachCR**
//! \~ \sa \a piForeach, \a piForeachC, \a piForeachR
#define piForeachRC(i, c) for (const i: PIReverseWrap(c))
#define piForeachRC(i, c) for(const i : PIReverseWrap(c))
#define piForeachCR piForeachRC
@@ -187,9 +177,7 @@ _PIReverseWrapper<C> PIReverseWrap(const C & c) {
//! \~russian Порядок обхода для функции изменения размерности reshape().
//! \~ \sa \a PIVector::reshape(), \a PIDeque::reshape()
enum ReshapeOrder {
ReshapeByRow /*! \~english Traversing elements by line, just as they stay in memory \~russian Обход элементов построчно, так же как они
находятся в памяти */
,
ReshapeByRow /*! \~english Traversing elements by line, just as they stay in memory \~russian Обход элементов построчно, так же как они находятся в памяти */,
ReshapeByColumn /*! \~english Traversing elements by column \~russian Обход элементов по столбцам */,
};

View File

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

View File

@@ -75,9 +75,9 @@
//! if the number of elements is known beforehand.
//!
//! The complexity (efficiency) of common operations on PIDeque is as follows:
//! - Random access - constant O(1)
//! - Insertion or removal of elements at the end or begin - amortized constant O(1)
//! - Insertion or removal of elements - linear in the distance to the end of the array O(n)
//! - 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
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
@@ -109,29 +109,31 @@
//! если количество элементов известно заранее.
//!
//! Сложность (эффективность) обычных операций над PIDeque следующая:
//! - Произвольный доступ — постоянная O(1)
//! - Вставка и удаление элементов в конце или начале — амортизированная постоянная O(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n)
//! - Произвольный доступ — постоянная 𝓞(1)
//! - Вставка и удаление элементов в конце или начале — амортизированная постоянная 𝓞(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n)
//!
//! \~\sa \a PIVector, \a PIMap
template<typename T>
template <typename T>
class PIDeque {
public:
typedef bool (*CompareFunc)(const T &, const T &);
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 T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
//! \~english Constructs an empty array.
//! \~russian Создает пустой массив.
inline PIDeque() { PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) }
inline PIDeque(): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIDeque(const PIDeque<T> & other) {
inline PIDeque(const PIDeque<T> & other): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
@@ -146,7 +148,7 @@ public:
//! PIDeque <int> v{1,2,3};
//! piCout << v; // {1, 2, 3}
//! \endcode
inline PIDeque(std::initializer_list<T> init_list) {
inline PIDeque(std::initializer_list<T> init_list): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(init_list.size());
newT(pid_data, init_list.begin(), init_list.size());
@@ -156,7 +158,7 @@ public:
//! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`.
inline PIDeque(const T * data, size_t size) {
inline PIDeque(const T * data, size_t size): pid_data(0), pid_size(0), pid_rsize(0), pid_start(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc_forward(size);
newT(pid_data + pid_start, data, pid_size);
@@ -164,9 +166,9 @@ public:
//! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `e`.
inline explicit PIDeque(size_t pid_size, const T & e = T()) {
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))
expand(pid_size, e);
resize(pid_size, e);
}
//! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
@@ -182,34 +184,31 @@ public:
//! 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) {
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))
expand(piv_size, f);
resize(piv_size, f);
}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIDeque(PIDeque<T> && other) {
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))
pid_data = other.pid_data;
pid_size = other.pid_size;
pid_rsize = other.pid_rsize;
pid_start = other.pid_start;
other._reset();
}
inline ~PIDeque() {
inline virtual ~PIDeque() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (pid_rsize))
deleteT(pid_data + pid_start, pid_size);
dealloc();
_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;
clear();
deleteT(pid_data + pid_start, pid_size);
alloc_forward(other.pid_size);
newT(pid_data + pid_start, other.pid_data + other.pid_start, pid_size);
return *this;
@@ -217,330 +216,360 @@ public:
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIDeque<T> & operator=(PIDeque<T> && other) {
inline PIDeque<T> & operator =(PIDeque<T> && other) {
swap(other);
return *this;
}
class iterator {
friend class PIDeque<T>;
private:
inline iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline iterator(): parent(0), pos(0) {}
inline T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline iterator & operator++() {
inline iterator & operator ++() {
++pos;
return *this;
}
inline iterator operator++(int) {
const auto tmp = *this;
inline iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline iterator & operator--() {
inline iterator & operator --() {
--pos;
return *this;
}
inline iterator operator--(int) {
const auto tmp = *this;
inline iterator operator --(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline iterator & operator+=(const iterator & it) {
inline iterator & operator +=(const iterator & it) {
pos += it.pos;
return *this;
}
inline iterator & operator+=(size_t p) {
inline iterator & operator +=(size_t p) {
pos += p;
return *this;
}
inline iterator & operator-=(const iterator & it) {
inline iterator & operator -=(const iterator & it) {
pos -= it.pos;
return *this;
}
inline iterator & operator-=(size_t p) {
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) {
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 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) {
friend inline iterator operator +(size_t p, const iterator & it) {return it + p;}
friend inline iterator operator +(const iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const iterator & it1, const iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const iterator & it1, const iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const iterator & it1, const iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const iterator & it1, const iterator & it2) { return it1.pos >= it2.pos; }
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const iterator & it1, const iterator & it2) {
return it1.pos < it2.pos;
}
friend inline bool operator <=(const iterator & it1, const iterator & it2) {
return it1.pos <= it2.pos;
}
friend inline bool operator >(const iterator & it1, const iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const iterator & it1, const iterator & it2) {
return it1.pos >= it2.pos;
}
};
class const_iterator {
friend class PIDeque<T>;
private:
inline const_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_iterator(): parent(0), pos(0) {}
inline const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline const T & operator *() const {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline const_iterator & operator++() {
inline const_iterator & operator ++() {
++pos;
return *this;
}
inline const_iterator operator++(int) {
const auto tmp = *this;
inline const_iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline const_iterator & operator--() {
inline const_iterator & operator --() {
--pos;
return *this;
}
inline const_iterator operator--(int) {
const auto tmp = *this;
inline const_iterator operator --(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline const_iterator & operator+=(const const_iterator & it) {
inline const_iterator & operator +=(const const_iterator & it) {
pos += it.pos;
return *this;
}
inline const_iterator & operator+=(size_t p) {
inline const_iterator & operator +=(size_t p) {
pos += p;
return *this;
}
inline const_iterator & operator-=(const const_iterator & it) {
inline const_iterator & operator -=(const const_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_iterator & operator-=(size_t p) {
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) {
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 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) {
friend inline const_iterator operator +(size_t p, const const_iterator & it) {return it + p;}
friend inline const_iterator operator +(const const_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const const_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; }
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const const_iterator & it1, const const_iterator & it2) {
return it1.pos < it2.pos;
}
friend inline bool operator <=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos <= it2.pos;
}
friend inline bool operator >(const const_iterator & it1, const const_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos >= it2.pos;
}
};
class reverse_iterator {
friend class PIDeque<T>;
private:
inline reverse_iterator(PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline reverse_iterator(): parent(0), pos(0) {}
inline T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline reverse_iterator & operator++() {
inline reverse_iterator & operator ++() {
--pos;
return *this;
}
inline reverse_iterator operator++(int) {
const auto tmp = *this;
inline reverse_iterator operator ++(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline reverse_iterator & operator--() {
inline reverse_iterator & operator --() {
++pos;
return *this;
}
inline reverse_iterator operator--(int) {
const auto tmp = *this;
inline reverse_iterator operator --(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline reverse_iterator & operator+=(const reverse_iterator & it) {
inline reverse_iterator & operator +=(const reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline reverse_iterator & operator+=(size_t p) {
inline reverse_iterator & operator +=(size_t p) {
pos -= p;
return *this;
}
inline reverse_iterator & operator-=(const reverse_iterator & it) {
inline reverse_iterator & operator -=(const reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline reverse_iterator & operator-=(size_t p) {
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) {
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 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) {
friend inline reverse_iterator operator +(size_t p, const reverse_iterator & it) {return it + p;}
friend inline reverse_iterator operator +(const reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos >= it2.pos; }
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos < it2.pos;
}
friend inline bool operator <=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos <= it2.pos;
}
friend inline bool operator >(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
};
class const_reverse_iterator {
friend class PIDeque<T>;
private:
inline const_reverse_iterator(const PIDeque<T> * v, ssize_t p): parent(v), pos(p) {}
const PIDeque<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_reverse_iterator(): parent(0), pos(0) {}
inline const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline const T & operator *() const {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline const_reverse_iterator & operator++() {
inline const_reverse_iterator & operator ++() {
--pos;
return *this;
}
inline const_reverse_iterator operator++(int) {
const auto tmp = *this;
inline const_reverse_iterator operator ++(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline const_reverse_iterator & operator--() {
inline const_reverse_iterator & operator --() {
++pos;
return *this;
}
inline const_reverse_iterator operator--(int) {
const auto tmp = *this;
inline const_reverse_iterator operator --(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline const_reverse_iterator & operator+=(const const_reverse_iterator & it) {
inline const_reverse_iterator & operator +=(const const_reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_reverse_iterator & operator+=(size_t p) {
inline const_reverse_iterator & operator +=(size_t p) {
pos -= p;
return *this;
}
inline const_reverse_iterator & operator-=(const const_reverse_iterator & it) {
inline const_reverse_iterator & operator -=(const const_reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline const_reverse_iterator & operator-=(size_t p) {
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) {
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) {
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) {
friend inline const_reverse_iterator operator +(size_t p, const const_reverse_iterator & it) {return it + p;}
friend inline const_reverse_iterator operator +(const const_reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos >= it2.pos; }
inline 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;
}
};
@@ -552,7 +581,7 @@ public:
//! \~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 Итератор на элемент, следующий за последним элементом.
@@ -564,10 +593,10 @@ public:
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\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 end() const { return const_iterator(this, pid_size); }
inline const_iterator begin() const {return const_iterator(this, 0); }
inline const_iterator end() const {return const_iterator(this, pid_size);}
//! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
@@ -580,12 +609,11 @@ public:
//! Если массив пустой, то совпадает с итератором \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 Обратный итератор на элемент,
//! следующий за последним элементом.
//! \~russian Обратный итератор на элемент, следующий за последним элементом.
//! \~\details ![rbegin, rend](doc/images/pivector_rbegin.png)
//!
//! \~english It corresponds to the element preceding the first element of the non-reversed array.
@@ -596,51 +624,51 @@ public:
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\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 rend() const { return const_reverse_iterator(this, -1); }
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, pid_size - 1);}
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
//! \~english Number of elements in the container.
//! \~russian Количество элементов массива.
//! \~\sa \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t size() const { return pid_size; }
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 Количество элементов, для которого сейчас выделена память массивом.
//! \~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 Проверяет пуст ли массив.
//! \~russian Проверяет пуст ли контейнер.
//! \~\return
//! \~english **true** if the container is empty, **false** otherwise
//! \~russian **true** если массив пуст, **false** иначе.
//! \~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);}
//! \~english Checks if the container has elements.
//! \~russian Проверяет не пуст ли массив.
//! \~russian Проверяет не пуст ли контейнер.
//! \~\return
//! \~english **true** if the container is not empty, **false** otherwise
//! \~russian **true** если массив не пуст, **false** иначе.
//! \~russian **true** если контейнер не пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isNotEmpty() const { return (pid_size > 0); }
inline bool isNotEmpty() const {return (pid_size > 0);}
//! \~english Tests whether at least one element in the array
//! passes the test implemented by the provided function `test`.
@@ -661,7 +689,7 @@ public:
//! \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) {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) return true;
}
return false;
@@ -686,7 +714,7 @@ public:
//! \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) {
for (ssize_t i = pid_start; i < pid_start + (ssize_t)pid_size; ++i) {
if (!test(pid_data[i])) return false;
}
return true;
@@ -708,8 +736,8 @@ public:
//! 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]; }
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`.
@@ -720,35 +748,7 @@ public:
//! \~russian Индекс элемента считается от `0`.
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline const T & at(size_t index) const { return pid_data[pid_start + index]; }
//! \~english Returns the first element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает первый элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a indexWhere()
inline const T & atWhere(std::function<bool(const T & e)> test, ssize_t start = 0, const T & def = T()) const {
const ssize_t i = indexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Returns the last element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает последний элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a lastIndexWhere()
inline const T & lastAtWhere(std::function<bool(const T & e)> test, ssize_t start = -1, const T & def = T()) const {
const ssize_t i = lastIndexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
inline const T & at(size_t index) const {return pid_data[pid_start + index];}
//! \~english Last element.
//! \~russian Последний элемент массива.
@@ -759,8 +759,8 @@ public:
//! \~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]; }
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 Первый элемент массива.
@@ -771,12 +771,12 @@ public:
//! \~russian Возвращает ссылку на пенрвый элемент в массиве.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline T & front() { return pid_data[pid_start]; }
inline const T & front() const { return pid_data[pid_start]; }
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 {
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;
@@ -786,7 +786,7 @@ public:
//! \~english Compare operator with array `v`.
//! \~russian Оператор сравнения с массивом `v`.
inline bool operator!=(const PIDeque<T> & v) const { return !(*this == v); }
inline bool operator !=(const PIDeque<T> & v) const {return !(*this == v);}
//! \~english Tests if element `e` exists in the array.
//! \~russian Проверяет наличие элемента `e` в массиве.
@@ -804,7 +804,7 @@ public:
//! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4};
@@ -825,39 +825,12 @@ public:
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) return true;
}
return false;
}
//! \~english Tests if all elements of `v` exists in the array.
//! \~russian Проверяет наличие всех элементов `v` в массиве.
//! \~\details
//! \~\code
//! PIDeque<int> v{1, 2, 3, 4};
//! piCout << v.contains({1,4}); // true
//! piCout << v.contains({1,5}); // false
//! \endcode
//! \~\sa \a every(), \a any(), \a entries(), \a forEach()
inline bool contains(const PIDeque<T> & v, ssize_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (const T & e: v) {
bool c = false;
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
if (e == pid_data[i]) {
c = true;
break;
}
}
if (!c) return false;
}
return true;
}
//! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details
@@ -874,7 +847,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<int> v{2, 2, 4, 2, 6};
@@ -883,13 +856,13 @@ public:
//! 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 {
inline int entries(const T & e, size_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) {
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) ++ec;
}
return ec;
@@ -914,16 +887,16 @@ public:
//! возвращается 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 {
inline int entries(std::function<bool(const T & e)> test, size_t start = 0) const {
int ec = 0;
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) ++ec;
}
return ec;
@@ -947,7 +920,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<int> v{2, 5, 9};
@@ -958,14 +931,14 @@ public:
//! 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 {
inline ssize_t indexOf(const T & e, size_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (e == pid_data[i]) {
return ssize_t(i) - pid_start;
return i - pid_start;
}
}
return -1;
@@ -990,7 +963,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIDeque<PIString> v{"do", "re", "mi", "re"};
@@ -999,14 +972,14 @@ public:
//! 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 {
inline ssize_t indexWhere(std::function<bool(const T & e)> test, size_t start = 0) const {
if (start < 0) {
start = pid_size + start;
if (start < 0) start = 0;
}
for (size_t i = pid_start + size_t(start); i < pid_start + pid_size; ++i) {
for (ssize_t i = pid_start + start; i < pid_start + (ssize_t)pid_size; ++i) {
if (test(pid_data[i])) {
return ssize_t(i) - pid_start;
return i - pid_start;
}
}
return -1;
@@ -1032,7 +1005,7 @@ public:
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
@@ -1049,9 +1022,9 @@ public:
inline ssize_t lastIndexOf(const T & e, ssize_t start = -1) const {
if (start >= size_s()) start = pid_size - 1;
if (start < 0) start = pid_size + start;
for (ssize_t i = ssize_t(pid_start) + start; i >= ssize_t(pid_start); --i) {
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
if (e == pid_data[i]) {
return i - ssize_t(pid_start);
return i - pid_start;
}
}
return -1;
@@ -1077,7 +1050,7 @@ public:
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
@@ -1085,9 +1058,9 @@ public:
inline ssize_t lastIndexWhere(std::function<bool(const T & e)> test, ssize_t start = -1) const {
if (start >= size_s()) start = pid_size - 1;
if (start < 0) start = pid_size + start;
for (ssize_t i = ssize_t(pid_start) + start; i >= ssize_t(pid_start); --i) {
for (ssize_t i = pid_start + start; i >= pid_start; --i) {
if (test(pid_data[i])) {
return i - ssize_t(pid_start);
return i - pid_start;
}
}
return -1;
@@ -1106,7 +1079,7 @@ public:
//! 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 Указатель на память массива только для чтения.
@@ -1125,7 +1098,7 @@ public:
//! 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 Создает подмассив, то есть кусок из текущего массива.
@@ -1146,7 +1119,7 @@ public:
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);
return PIDeque(&(pid_data[pid_start + index]), count);
}
//! \~english Clear array, remove all elements.
@@ -1156,14 +1129,16 @@ public:
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & clear() {
deleteT(pid_data + pid_start, pid_size);
pid_size = 0;
pid_start = (pid_rsize - pid_size) / 2;
resize(0);
return *this;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, pid_size)
pid_size = 0;
@@ -1210,17 +1185,21 @@ public:
//! \~english Same as \a fill().
//! \~russian Тоже самое что и \a fill().
//! \~\sa \a fill(), \a resize()
inline PIDeque<T> & assign(const T & e = T()) { return fill(e); }
inline PIDeque<T> & assign(const T & e = T()) {return fill(e);}
//! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & e) {
resize(new_size);
return fill(e);
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & assign(size_t new_size, const T & e) {
_resizeRaw(new_size);
return fill(e);
@@ -1238,12 +1217,20 @@ public:
//! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, const T & e = T()) {
if (new_size == 0) return clear();
if (new_size < pid_size) {
deleteT(pid_data + pid_start + new_size, pid_size - new_size);
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size;
} else if (new_size > pid_size) {
expand(new_size, e);
if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2;
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, e);
}
}
return *this;
}
@@ -1260,31 +1247,41 @@ public:
//! лишние элементы удаляются с конца массива.
//! \~\sa \a size(), \a clear()
inline PIDeque<T> & resize(size_t new_size, std::function<T(size_t i)> f) {
if (new_size == 0) return clear();
if (new_size < pid_size) {
deleteT(pid_data + pid_start + new_size, pid_size - new_size);
deleteT(&(pid_data[new_size + pid_start]), pid_size - new_size);
pid_size = new_size;
} else if (new_size > pid_size) {
expand(new_size, f);
if (new_size == 0) {
pid_start = (pid_rsize - pid_size) / 2;
}
}
if (new_size > pid_size) {
size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f(i));
}
}
return *this;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIDeque<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
if (new_size > pid_size) {
PIINTROSPECTION_CONTAINER_USED(T, (new_size - pid_size));
PIINTROSPECTION_CONTAINER_USED(T, (new_size-pid_size));
}
if (new_size < pid_size) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size - new_size));
PIINTROSPECTION_CONTAINER_UNUSED(T, (pid_size-new_size));
}
#endif
alloc_forward(new_size);
return *this;
}
inline void _copyRaw(T * dst, const T * src, size_t size) { newT(dst, src, size); }
inline void _copyRaw(T * dst, const T * src, size_t size) {
newT(dst, src, size);
}
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
@@ -1302,7 +1299,7 @@ public:
//! \~\sa \a size(), \a capacity(), \a resize()
inline PIDeque<T> & reserve(size_t new_size) {
if (new_size <= pid_rsize) return *this;
const size_t os = pid_size;
size_t os = pid_size;
alloc_forward(new_size);
pid_size = os;
return *this;
@@ -1322,21 +1319,17 @@ public:
inline PIDeque<T> & insert(size_t index, const T & e = T()) {
if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1)
const bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc_forward(pid_size + 1);
if (index < pid_size - 1) {
const size_t os = pid_size - index - 1;
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
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(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<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, e);
@@ -1352,21 +1345,17 @@ public:
inline PIDeque<T> & insert(size_t index, T && e) {
if (index == pid_size) return push_back(e);
PIINTROSPECTION_CONTAINER_USED(T, 1)
const bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
alloc_forward(pid_size + 1);
if (index < pid_size - 1) {
const size_t os = pid_size - index - 1;
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + 1),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
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(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<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, std::move(e));
@@ -1383,25 +1372,21 @@ public:
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
fprintf(stderr, "error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
printf("error with PIDeque<%s>::insert\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const bool dir = v.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
const ssize_t os = pid_size - index;
ssize_t os = pid_size - index;
alloc_forward(pid_size + v.pid_size);
if (os > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + v.pid_size),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
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(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + v.pid_size),
index * sizeof(T));
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);
@@ -1419,22 +1404,17 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIDeque<T> & insert(size_t index, std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const bool dir = init_list.size() > pid_size ? true : (index >= pid_rsize / 2 ? true : false);
bool dir = pid_rsize <= 2 ? true : (index >= pid_rsize / 2 ? true : false);
if (dir) {
const ssize_t os = ssize_t(pid_size) - index;
ssize_t os = pid_size - index;
alloc_forward(pid_size + init_list.size());
if (os > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index + init_list.size()),
reinterpret_cast<const void *>(pid_data + pid_start + index),
os * sizeof(T));
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(reinterpret_cast<void *>(pid_data + pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + init_list.size()),
index * sizeof(T));
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());
@@ -1453,27 +1433,22 @@ public:
inline PIDeque<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this;
if (index + count >= pid_size) {
if (index < pid_size) {
deleteT(pid_data + pid_start + index, pid_size - index);
pid_size = index;
resize(index);
return *this;
}
size_t os = pid_size - index - count;
deleteT(&(pid_data[index + pid_start]), count);
if (os <= index) {
if (os > 0) {
memmove((void*)(&(pid_data[index + pid_start])), (const void*)(&(pid_data[index + pid_start + count])), os * sizeof(T));
}
} else {
const size_t os = pid_size - index - count;
deleteT(pid_data + pid_start + index, count);
if (os <= index) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index),
reinterpret_cast<const void *>(pid_data + pid_start + index + count),
os * sizeof(T));
} else {
if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + count),
reinterpret_cast<const void *>(pid_data + pid_start),
index * sizeof(T));
memmove((void*)(&(pid_data[pid_start + count])), (const void*)(&(pid_data[pid_start])), index * sizeof(T));
}
pid_start += count;
}
pid_size -= count;
}
return *this;
}
@@ -1483,10 +1458,10 @@ public:
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIDeque<T> & other) {
piSwap<T *>(pid_data, other.pid_data);
piSwap<T*>(pid_data, other.pid_data);
piSwap<size_t>(pid_size, other.pid_size);
piSwap<size_t>(pid_rsize, other.pid_rsize);
piSwap<size_t>(pid_start, other.pid_start);
piSwap<ssize_t>(pid_start, other.pid_start);
}
//! \~english Sorts the elements in non-descending order.
@@ -1528,18 +1503,23 @@ public:
//! 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))`.
//! Функция сравнения, возвращает `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) {
inline PIDeque<T> & sort(std::function<bool(const T &a, const T &b)> comp) {
std::sort(begin(), end(), comp);
return *this;
}
@@ -1562,9 +1542,9 @@ public:
//! \endcode
//! \~\sa \a reversed()
inline PIDeque<T> & reverse() {
const size_t s2 = pid_size / 2;
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]);
piSwap<T>(pid_data[pid_start+i], pid_data[pid_start+pid_size-i-1]);
}
return *this;
}
@@ -1592,12 +1572,10 @@ public:
//! Если `add_size < 0`, то с конца массива удаляются элементы.
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize()
inline PIDeque<T> & enlarge(ssize_t add_size, const T & e = T()) {
const ssize_t ns = size_s() + add_size;
if (ns <= 0)
clear();
else
resize(size_t(ns), e);
inline PIDeque<T> & enlarge(llong pid_size) {
llong ns = size_s() + pid_size;
if (ns <= 0) clear();
else resize(size_t(ns));
return *this;
}
@@ -1630,15 +1608,12 @@ public:
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeAll(const T & e) {
ssize_t j = indexOf(e);
if (j != -1) {
for (size_t i = j + 1; i < pid_size; ++i) {
if (pid_data[i + pid_start] != e) {
pid_data[j++ + pid_start] = std::move(pid_data[i + pid_start]);
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (pid_data[i + pid_start] == e) {
remove(i);
--i;
}
}
remove(j, pid_size - j);
}
return *this;
}
@@ -1654,15 +1629,12 @@ public:
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIDeque<T> & removeWhere(std::function<bool(const T & e)> test) {
ssize_t j = indexWhere(test);
if (j != -1) {
for (size_t i = j + 1; i < pid_size; ++i) {
if (!test(pid_data[i + pid_start])) {
pid_data[j++ + pid_start] = std::move(pid_data[i + pid_start]);
for (ssize_t i = 0; i < ssize_t(pid_size); ++i) {
if (test(pid_data[i + pid_start])) {
remove(i);
--i;
}
}
remove(j, pid_size - j);
}
return *this;
}
@@ -1721,8 +1693,7 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back()
inline PIDeque<T> & push_back(std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const size_t ps = pid_size;
size_t ps = pid_size;
alloc_forward(pid_size + init_list.size());
newT(pid_data + pid_start + ps, init_list.begin(), init_list.size());
return *this;
@@ -1735,14 +1706,13 @@ public:
//! \~russian Перегруженая функция.
//! \~\sa \a push_back()
inline PIDeque<T> & push_back(const PIDeque<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
fprintf(stderr, "error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
printf("error with PIDeque<%s>::append\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const size_t ps = pid_size;
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;
@@ -1772,7 +1742,7 @@ public:
//! 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 PIDeque<T> & append(const T & e) {return push_back(e);}
//! \~english Appends the given element `e` to the end of the array.
//! \~russian Добавляет элемент `e` в конец массива.
@@ -1780,7 +1750,7 @@ public:
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a append()
inline PIDeque<T> & append(T && e) { return push_back(std::move(e)); }
inline PIDeque<T> & append(T && e) {return push_back(std::move(e));}
//! \~english Appends the given elements to the end of the array.
//! \~russian Добавляет элементы в конец массива.
@@ -1792,7 +1762,7 @@ public:
//! Добавляет элементы из
//! [списка инициализации 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); }
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` в конец массива.
@@ -1805,7 +1775,7 @@ public:
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIDeque<T> & append(const PIDeque<T> & v) { return push_back(v); }
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` в конец массива.
@@ -1816,7 +1786,7 @@ public:
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIDeque<T> & operator<<(const T & e) { return push_back(e); }
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` в конец массива.
@@ -1827,7 +1797,7 @@ public:
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIDeque<T> & operator<<(T && e) { return push_back(std::move(e)); }
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` в конец массива.
@@ -1838,7 +1808,7 @@ public:
//! 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); }
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` в начало массива.
@@ -1865,9 +1835,7 @@ public:
//! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIDeque<T> & push_front(const T & e) {
if (isEmpty()) return push_back(e);
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, e);
insert(0, e);
return *this;
}
@@ -1878,9 +1846,7 @@ public:
//! \~russian Перегруженая функция.
//! \~\sa \a push_front()
inline PIDeque<T> & push_front(T && e) {
if (isEmpty()) return push_back(std::move(e));
alloc_backward(pid_size + 1, -1);
elementNew(pid_data + pid_start, std::move(e));
insert(0, std::move(e));
return *this;
}
@@ -1895,7 +1861,10 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a push_front()
inline PIDeque<T> & push_front(const PIDeque<T> & v) { return insert(0, v); }
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 Добавляет элементы в начало массива.
@@ -1907,7 +1876,10 @@ public:
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIDeque<T> & push_front(std::initializer_list<T> init_list) { return insert(0, init_list); }
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` в начало массива.
@@ -1933,7 +1905,7 @@ public:
//! 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); }
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` в начало массива.
@@ -1941,7 +1913,7 @@ public:
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a prepend()
inline PIDeque<T> & prepend(T && e) { return push_front(std::move(e)); }
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` в начало массива.
@@ -1954,7 +1926,7 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a prepend()
inline PIDeque<T> & prepend(const PIDeque<T> & v) { return push_front(v); }
inline PIDeque<T> & prepend(const PIDeque<T> & v) {return push_front(v);}
//! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива.
@@ -1966,7 +1938,7 @@ public:
//! Добавляет элементы из
//! [списка инициализации 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); }
inline PIDeque<T> & prepend(std::initializer_list<T> init_list) {return prepend(init_list);}
//! \~english Remove one element from the end of the array.
//! \~russian Удаляет один элемент с конца массива.
@@ -1983,8 +1955,7 @@ public:
//! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_back() {
if (pid_size == 0) return *this;
elementDelete(pid_data[pid_size + pid_start - 1]);
pid_size = pid_size - 1;
resize(pid_size - 1);
return *this;
}
@@ -2005,9 +1976,7 @@ public:
//! \~\sa \a pop_back(), \a take_back(), \a take_front()
inline PIDeque<T> & pop_front() {
if (pid_size == 0) return *this;
elementDelete(pid_data[pid_start]);
pid_start += 1;
pid_size -= 1;
remove(0);
return *this;
}
@@ -2021,7 +1990,7 @@ public:
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() {
const T e(back());
T e(back());
pop_back();
return e;
}
@@ -2036,7 +2005,7 @@ public:
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() {
const T e(front());
T e(front());
pop_front();
return e;
}
@@ -2050,10 +2019,9 @@ public:
//! piCout << v2; // {1, 2, 3}
//! \endcode
//! \~\sa \a map()
template<typename ST>
template <typename ST>
inline PIDeque<ST> toType() const {
PIDeque<ST> ret(pid_size);
ret.reserve(pid_size);
for (size_t i = 0; i < pid_size; ++i) {
ret[i] = ST(pid_data[i + pid_start]);
}
@@ -2061,9 +2029,9 @@ public:
}
//! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `bool test(const T & e)`.
//! that pass the test implemented by the provided function `test`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`.
//! прошедшими проверку, задаваемую в передаваемой функции `test`.
//! \~\details
//! \~\code
//! PIDeque<int> v{3, 2, 5, 2, 7};
@@ -2079,39 +2047,6 @@ public:
return ret;
}
//! \~english Same as \a filter() but with `index` parameter in `test`.
//! \~russian Аналогично \a filter() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filter()
inline PIDeque<T> filterIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIDeque<T> ret;
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
if (test(i - pid_start, pid_data[i])) ret << pid_data[i];
}
return ret;
}
//! \~english Same as \a filter() but from end to begin (from right to left).
//! \~russian Аналогично \a filter() но от конца до начала (справа на лево).
//! \~\sa \a filter()
inline PIDeque<T> filterReverse(std::function<bool(const T & e)> test) const {
PIDeque<T> ret;
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
if (test(pid_data[i])) ret << pid_data[i];
}
return ret;
}
//! \~english Same as \a filterReverse() but with `index` parameter in `test`.
//! \~russian Аналогично \a filterReverse() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filterReverse()
inline PIDeque<T> filterReverseIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIDeque<T> ret;
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
if (test(i - pid_start, pid_data[i])) ret << pid_data[i];
}
return ret;
}
//! \~english Execute function `void f(const T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details
@@ -2152,63 +2087,6 @@ public:
return *this;
}
//! \~english Same as \a forEach() but with `index` parameter in `f`.
//! \~russian Аналогично \a forEach() но с параметром индекса `index` в функции `f`.
//! \~\sa \a forEach()
inline void forEachIndexed(std::function<void(size_t index, const T & e)> f) const {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
f(i - pid_start, pid_data[i]);
}
}
//! \~english Same as \a forEachIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachIndexed()
inline PIDeque<T> & forEachIndexed(std::function<void(size_t index, T & e)> f) {
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
f(i - pid_start, pid_data[i]);
}
return *this;
}
//! \~english Same as \a forEach() but from end to begin (from right to left).
//! \~russian Аналогично \a forEach() но от конца до начала (справа на лево).
//! \~\sa \a forEach()
inline void forEachReverse(std::function<void(const T & e)> f) const {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(pid_data[i]);
}
}
//! \~english Same as \a forEachReverse(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverse(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachReverse()
inline PIDeque<T> & forEachReverse(std::function<void(T & e)> f) {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(pid_data[i]);
}
return *this;
}
//! \~english Same as \a forEachIndexed() but from end to begin (from right to left).
//! \~russian Аналогично \a forEachIndexed() но от конца до начала (справа на лево).
//! \~\sa \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline void forEachReverseIndexed(std::function<void(size_t index, const T & e)> f) const {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(i - pid_start, pid_data[i]);
}
}
//! \~english Same as \a forEachReverseIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverseIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEachReverseIndexed(), \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline PIDeque<T> & forEachReverseIndexed(std::function<void(size_t index, T & e)> f) {
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
f(i - pid_start, pid_data[i]);
}
return *this;
}
//! \~english Сreates a new array populated with the results
//! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции
@@ -2218,78 +2096,23 @@ public:
//! 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"}
//! piCout << sl; {"1", "2", "3"}
//! \endcode
//! \~\sa \a forEach(), \a reduce()
template<typename ST>
template <typename ST>
inline PIDeque<ST> map(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret;
ret.reserve(pid_size);
PIDeque<ST> ret; ret.reserve(pid_size);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret << f(pid_data[i]);
}
return ret;
}
//! \~english Same as \a map() but with `index` parameter in `f`.
//! \~russian Аналогично \a map() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.mapIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"0", "1", "2"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIDeque<ST> mapIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIDeque<ST> ret;
ret.reserve(pid_size);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret << f(i - pid_start, pid_data[i]);
}
return ret;
}
//! \~english Same as \a map() but from end to begin (from right to left).
//! \~russian Аналогично \a map() но от конца до начала (справа на лево).
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.mapReverse<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"3", "2", "1"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIDeque<ST> mapReverse(std::function<ST(const T & e)> f) const {
PIDeque<ST> ret;
ret.reserve(pid_size);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret << f(pid_data[i]);
}
return ret;
}
//! \~english Same as \a mapReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a mapReverse() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIDeque<int> v{1, 2, 3};
//! PIStringList sl = v.mapReverseIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"2", "1", "0"}
//! \endcode
//! \~\sa \a mapReverse()
template<typename ST>
inline PIDeque<ST> mapReverseIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIDeque<ST> ret;
ret.reserve(pid_size);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret << f(size_t(i) - pid_start, pid_data[i]);
}
return ret;
}
//! \~english Applies the function `ST f(const T & e, const ST & acc)`
//! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
@@ -2310,7 +2133,7 @@ public:
//! \param initial _optional_ Object used as the second argument
//! when the `f` function is first called.
//! \~russian Метод reduce() выполняет функцию `f`
//! один раз для каждого элемента, присутствующего в массиве от начала к концу (слева на право).
//! один раз для каждого элемента, присутствующего в массиве.
//! Если при вызове reduce() передан аргумент `initial`,
//! то при первом вызове функции `f` значение `acc`
//! будет равным значению `initial`.
@@ -2330,8 +2153,8 @@ public:
//! int s = v.reduce<int>([](const int & e, const int & acc){return e + acc;});
//! piCout << s; // 15
//! \endcode
//! \~\sa \a reduceIndexed(), \a reduceReverse(), \a reduceReverseIndexed(), \a forEach(), \a map()
template<typename ST>
//! \~\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) {
@@ -2340,42 +2163,6 @@ public:
return ret;
}
//! \~english Same as \a reduce() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduce() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = pid_start; i < pid_start + pid_size; ++i) {
ret = f(i - pid_start, pid_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduce() but from end to begin (from right to left).
//! \~russian Аналогично \a reduce() но от конца до начала (справа на лево).
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceReverse(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret = f(pid_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduceReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduceReverse() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduceReverse()
template<typename ST>
inline ST reduceReverseIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = ssize_t(pid_start + pid_size) - 1; i >= ssize_t(pid_start); --i) {
ret = f(size_t(i) - pid_start, pid_data[i], ret);
}
return ret;
}
//! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details
@@ -2399,22 +2186,22 @@ public:
PIDeque<PIDeque<T>> ret;
if (isEmpty()) return ret;
#ifndef NDEBUG
if (rows * cols != pid_size) {
fprintf(stderr, "error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
if (rows*cols != pid_size) {
printf("error with PIDeque<%s>::reshape\n", __PIP_TYPENAME__(T));
}
#endif
assert(rows * cols == pid_size);
ret.expand(rows);
assert(rows*cols == pid_size);
ret.resize(rows);
if (order == ReshapeByRow) {
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 == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) {
ret[r].expand(cols);
ret[r].resize(cols);
for (size_t c = 0; c < cols; c++) {
ret[r][c] = pid_data[c * rows + r];
ret[r][c] = pid_data[c*rows + r];
}
}
}
@@ -2435,12 +2222,14 @@ public:
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if<std::is_same<T, PIDeque<C>>::value, int>::type = 0>
template<typename C, typename std::enable_if<
std::is_same<T, PIDeque<C>>::value
, int>::type = 0>
inline PIDeque<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> ret;
if (isEmpty()) return ret;
const size_t rows = size();
const size_t cols = at(0).size();
size_t rows = size();
size_t cols = at(0).size();
ret.reserve(rows * cols);
if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) {
@@ -2476,220 +2265,119 @@ public:
//! 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>
template<typename C, typename std::enable_if<
std::is_same<T, PIDeque<C>>::value
, int>::type = 0>
inline PIDeque<PIDeque<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
PIDeque<C> fl = flatten<C>();
return fl.reshape(rows, cols, order);
}
//! \~english Divides an array into a two-dimensional array using the separator `separator`.
//! \~russian Разделяет массив на двумерный массив с помощью разделителя`separator`.
//! \~\code
//! PIDeque<int> v{1, 2, 3, 99, 4, 5, 99, 6};
//! piCout << v.split(99); // {{1, 2, 3}, {4, 5}, {6}}
//! \endcode
//! \~\sa \a splitBySize()
inline PIDeque<PIDeque<T>> split(const T & separator) const {
PIDeque<PIDeque<T>> ret;
if (isEmpty()) return ret;
size_t start = 0;
ssize_t ci = indexOf(separator, start);
while (ci >= 0) {
ret << PIDeque<T>(pid_data + pid_start + start, ci - start);
start = ci + 1;
ci = indexOf(separator, start);
}
if (start < pid_size) {
ret << PIDeque<T>(pid_data + pid_start + start, pid_size - start);
}
return ret;
}
//! \~english Divides an array into a two-dimensional array in chunks of no more than `sz`.
//! \~russian Разделяет массив на двумерный массив по кускам не более чем `sz`.
//! \~\sa \a split()
inline PIDeque<PIDeque<T>> splitBySize(size_t sz) const {
PIDeque<PIDeque<T>> ret;
if (isEmpty() || sz == 0) return ret;
const size_t ch = pid_size / sz;
for (size_t i = 0; i < ch; ++i) {
ret << PIDeque<T>(pid_data + pid_start + sz * i, sz);
}
const size_t t = ch * sz;
if (t < pid_size) {
ret << PIDeque<T>(pid_data + pid_start + t, pid_size - t);
}
return ret;
}
//! \~english Cut sub-array of this array.
//! \~russian Вырезает подмассив, то есть кусок из текущего массива.
//! \~english
//! \param index - index of this array where sub-array starts
//! \param count - sub-array size
//! \~russian
//! \param index - индекс в текущем массиве, откуда начинётся подмассив
//! \param count - размер подмассива
//! \~\details
//! \~english
//! Index must be in range from `0` to `size()-1`.
//! If sub-array size more than this array size, than ends early.
//! \~russian
//! Индекс начала должен лежать в диапазоне от `0` до `size()-1`.
//! Если заданный размер подмассива превышает размер текущего массива,
//! то вернется подмассив меньшего размера (`size()-index-1`).
inline PIDeque<T> takeRange(size_t index, size_t count) {
PIDeque<T> ret;
if (index >= pid_size || count == 0) return ret;
if (index + count > pid_size) count = pid_size - index;
ret.alloc_forward(count);
memcpy(reinterpret_cast<void *>(ret.pid_data + ret.pid_start),
reinterpret_cast<const void *>(pid_data + pid_start + index),
count * sizeof(T));
const size_t os = pid_size - index - count;
if (os <= index) {
if (os > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + index),
reinterpret_cast<const void *>(pid_data + pid_start + index + count),
os * sizeof(T));
}
} else {
if (index > 0) {
memmove(reinterpret_cast<void *>(pid_data + pid_start + count),
reinterpret_cast<const void *>(pid_data + pid_start),
index * sizeof(T));
}
pid_start += count;
}
pid_size -= count;
return ret;
}
private:
inline void _reset() {
pid_size = 0;
pid_rsize = 0;
pid_start = 0;
pid_data = nullptr;
}
inline void _reset() {pid_size = pid_rsize = pid_start = 0; pid_data = 0;}
inline size_t asize(ssize_t s) {
if (s <= 0) return 0;
if (pid_rsize * 2 >= size_t(s) && pid_rsize < size_t(s)) {
return pid_rsize * 2;
if (pid_rsize + pid_rsize >= size_t(s) && pid_rsize < size_t(s)) {
return pid_rsize + pid_rsize;
}
size_t t = _PIContainerConstants<T>::minCountPoT();
s -= 1;
while (s >> t) {
ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
while (s_ >> t)
++t;
}
return (1 << t);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
for (size_t i = 0; i < s; ++i) {
for (size_t i = 0; i < s; ++i)
elementNew(dst + i, src[i]);
}
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<const void *>(src), s * sizeof(T));
memcpy((void*)(dst), (const void*)(src), s * sizeof(T));
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if (d != nullptr) {
if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]);
}
}
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, const T & from) {
new (to) T(from);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
new (to) T(std::move(from));
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {
(*to) = from;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
(*to) = std::move(from);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementDelete(T & from) {
from.~T();
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, const T & from) {new(to)T(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {new(to)T(std::move(from));}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {(*to) = from;}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {(*to) = std::move(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {from.~T();}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {}
inline void dealloc() {
if (pid_data != nullptr) {
free(reinterpret_cast<void *>(pid_data));
pid_data = nullptr;
if ((uchar*)pid_data != 0) free((uchar*)pid_data);
pid_data = 0;
}
}
inline void checkMove() {
if (pid_size >= 4) {
if (pid_size < pid_rsize / 6) {
if (pid_start < (pid_size * 2) || ssize_t(pid_start) > (ssize_t(pid_rsize) - (ssize_t(pid_size) * 2))) {
size_t ns = (pid_rsize - pid_size) / 2;
if (pid_start < ssize_t(pid_size + pid_size) || pid_start > (ssize_t(pid_rsize) - ssize_t(pid_size) - ssize_t(pid_size))) {
ssize_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) {
memmove(reinterpret_cast<void *>(pid_data + ns),
reinterpret_cast<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;
}
}
}
} else {
const size_t ns = (pid_rsize - pid_size) / 2;
ssize_t ns = (pid_rsize - pid_size) / 2;
if (pid_start != ns) {
memmove(reinterpret_cast<void *>(pid_data + ns),
reinterpret_cast<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;
}
}
}
inline void alloc_forward(size_t new_size) {
inline void alloc_forward(size_t new_size) { // direction == true -> alloc forward
if (pid_start + new_size <= pid_rsize) {
pid_size = new_size;
if (pid_start > 0) checkMove();
checkMove();
return;
}
pid_size = new_size;
const size_t as = asize(pid_start + new_size);
size_t as = asize(pid_start + new_size);
if (as != pid_rsize) {
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(pid_data), as * sizeof(T)));
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
T * p_d = (T*)(realloc((void*)(pid_data), as*sizeof(T)));
#ifndef NDEBUG
if (!p_d) {
fprintf(stderr, "error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
printf("error with PIDeque<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
@@ -2697,15 +2385,19 @@ private:
pid_rsize = as;
}
}
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) {
const size_t as = ssize_t(pid_start) + start_offset < 0 ? asize(pid_rsize - start_offset) : pid_rsize;
inline void alloc_backward(size_t new_size, ssize_t start_offset = 0) { //alloc backward
size_t as;
if (pid_start + start_offset < 0) {
as = asize(pid_rsize - start_offset);
} else {
as = pid_rsize;
}
if (as > pid_rsize) {
T * td = reinterpret_cast<T *>(malloc(as * sizeof(T)));
const size_t ns = pid_start + as - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - pid_rsize))
T * td = (T*)(malloc(as * sizeof(T)));
ssize_t ns = pid_start + as - pid_rsize;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-pid_rsize))
if (pid_rsize > 0 && pid_data != 0) {
memcpy(reinterpret_cast<void *>(td + ns), reinterpret_cast<const void *>(pid_data + pid_start), pid_size * sizeof(T));
memcpy((void*)(td + ns), (const void*)(pid_data + pid_start), pid_size * sizeof(T));
dealloc();
}
pid_data = td;
@@ -2717,28 +2409,9 @@ private:
checkMove();
}
inline void expand(size_t new_size, const T & e = T()) {
const size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, e);
}
}
inline void expand(size_t new_size, std::function<T(size_t i)> f) {
const size_t os = pid_size;
alloc_forward(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os + pid_start; i < new_size + pid_start; ++i) {
elementNew(pid_data + i, f(i));
}
}
T * pid_data = nullptr;
size_t pid_size = 0;
size_t pid_rsize = 0;
size_t pid_start = 0;
T * pid_data;
size_t pid_size, pid_rsize;
ssize_t pid_start;
};
@@ -2746,7 +2419,7 @@ private:
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename T>
inline std::ostream & operator<<(std::ostream & s, const PIDeque<T> & v) {
inline std::ostream & operator <<(std::ostream & s, const PIDeque<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
@@ -2762,23 +2435,21 @@ inline std::ostream & operator<<(std::ostream & s, const PIDeque<T> & v) {
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename T>
inline PICout operator<<(PICout s, const PIDeque<T> & v) {
inline PICout operator <<(PICout s, const PIDeque<T> & v) {
s.space();
s.saveAndSetControls(0);
s.setControl(0, true);
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
if (i < v.size() - 1) s << ", ";
}
s << "}";
s.restoreControls();
s.restoreControl();
return s;
}
template<typename T>
inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {
f.swap(s);
}
inline void piSwap(PIDeque<T> & f, PIDeque<T> & s) {f.swap(s);}
#endif // PIDEQUE_H

View File

@@ -0,0 +1,187 @@
/** \class PIMap
* \brief Associative array
* \details This class used to store Key = Value array of any
* type of data. \a value() returns value for key and leave map
* unchaged in any case. \a operator [] create entry in map if
* there is no entry for given key. You can retrieve all
* keys by method \a keys() and all values by methos \a values().
* To iterate all entries use class PIMapIterator, or methods
* \a makeIterator() and \a makeReverseIterator().
* \fn PIMap::PIMap();
* \brief Contructs an empty map
* \fn PIMap::PIMap(const PIMap & other);
* \brief Contructs a copy of "other"
* \fn PIMap & PIMap::operator =(const PIMap & other);
* \brief Copy operator
* \fn PIMap::PIMap(const PIMap & other);
* \brief Contructs a copy of "other"
* \fn PIMapIterator PIMap::makeIterator() const
* \brief Returns PIMapIterator for this map
* \fn PIMapIterator PIMap::makeReverseIterator() const
* \brief Returns reverse PIMapIterator for this map
* \fn size_t PIMap::size() const
* \brief Returns entries count
* \fn int PIMap::size_s() const
* \brief Returns entries count
* \fn size_t PIMap::length() const
* \brief Returns entries count
* \fn bool PIMap::isEmpty() const
* \brief Returns if map is empty
* \fn T & PIMap::operator [](const Key & key)
* \brief Returns value for key "key". If there is no key in map, create one.
* \fn const T PIMap::operator [](const Key & key) const
* \brief Returns value for key "key". If there is no key in map, returns default T().
* \fn T & PIMap::at(const Key & key)
* \brief Equivalent to operator []
* \fn const T PIMap::at(const Key & key) const
* \brief Equivalent to operator []
* \fn PIMap & PIMap::operator <<(const PIMap & other)
* \brief Insert all etries of "other" to this map. Override existing values.
* \fn bool PIMap::operator ==(const PIMap & t) const
* \brief Compare operator
* \fn bool PIMap::operator !=(const PIMap & t) const
* \brief Compare operator
* \fn bool PIMap::contains(const Key & key) const
* \brief Returns "true" if map contains entry with key "key"
* \fn PIMap & PIMap::reserve(size_t new_size)
* \brief Reserve space for "new_size" entries
* \fn PIMap & PIMap::removeOne(const Key & key)
* \brief Remove entry with key "key"
* \fn PIMap & PIMap::remove(const Key & key)
* \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::erase(const Key & key)
* \brief Equivalent \a removeOne(key)
* \fn PIMap & PIMap::clear()
* \brief Clear map
* \fn void PIMap::swap(PIMap & other)
* \brief Swap map with "other"
* \fn PIMap & PIMap::insert(const Key & key, const T & value)
* \brief Insert or rewrite entry with key "key" and value "value"
* \fn const T PIMap::value(const Key & key, const T & default = T())
* \brief Returns value for key "key". If there is no key in map, returns "default".
* \fn PIVector<T> PIMap::values() const
* \brief Returns all values as PIVector
* \fn Key PIMap::key(const T & value, const Key & default = Key()) const
* \brief Returns key for first founded value "value". If there is no such value in map, returns "default".
* \fn PIVector<Key> PIMap::keys() const
* \brief Returns all keys as PIVector
* */
/** \class PIMapIterator
* \brief Helper class to iterate over PIMap
* \details This class used to access keys and values in PIMap.
* You can use constructor to create iterator, or use \a PIMap::makeIterator()
* and \a PIMap::makeReverseIterator() methods.
*
* First usage variant:
* \code
* PIMap<int, PIString> m;
* m[1] = "one";
* m[2] = "two";
* m[4] = "four";
*
* auto it = m.makeIterator();
* while (it.next()) {
* piCout << it.key() << it.value();
* }
* // 1 one
* // 2 two
* // 4 four
* \endcode
*
* Using hasNext():
* \code
* while (it.hasNext()) {
* it.next();
* \endcode
*
* Using constructor:
* \code
* PIMapIterator<int, PIString> it(m);
* \endcode
*
* Write access:
* \code
* while (it.next()) {
* it.valueRef().append("_!");
* piCout << it.key() << it.value();
* }
*
* // 1 one_!
* // 2 two_!
* // 4 four_!
* \endcode
*
* Reverse iterator:
* \code
* auto it = m.makeReverseIterator();
* while (it.next()) {
* piCout << it.key() << it.value();
* }
*
* // 4 four
* // 2 two
* // 1 one
* \endcode
* \fn PIMapIterator(const PIMap & map, bool reverse = false)
* \brief Contructs iterator for "map". Current position is invalid.
* \fn const Key & PIMapIterator::key() const
* \brief Returns current entry key
* \fn const T & PIMapIterator::value() const
* \brief Returns current entry value
* \fn T & PIMapIterator::valueRef() const
* \brief Returns reference to current entry value
* \fn bool PIMapIterator::hasNext()
* \brief Returns if iterator can jump to next entry
* \fn bool PIMapIterator::next()
* \brief Jump to next entry and return if new position is valid.
* \fn void PIMapIterator::reset()
* \brief Reset iterator to initial position.
* */

View File

@@ -1,17 +1,8 @@
//! \addtogroup Containers
//! \{
//! \file pimap.h
//! \brief
//! \~english Declares \a PIMap
//! \~russian Объявление \a PIMap
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//! \~\}
/*! \file pimap.h
* \brief Associative array with custom types of key and value
*
* This file declares PIMap
*/
/*
PIP - Platform Independent Primitives
Associative array with custom types of key and value
@@ -34,977 +25,366 @@
#ifndef PIMAP_H
#define PIMAP_H
#include "pivector.h"
#include "pideque.h"
#include "pipair.h"
#include "pivector.h"
template<typename Key, typename T>
class PIMapIteratorConst;
template<typename Key, typename T>
class PIMapIteratorConstReverse;
template<typename Key, typename T>
template <typename Key, typename T>
class PIMapIterator;
template<typename Key, typename T>
class PIMapIteratorReverse;
//! \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 {
template<typename Key1, typename T1>
friend class PIMapIteratorConst;
template<typename Key1, typename T1>
friend class PIMapIteratorConstReverse;
template<typename Key1, typename T1>
friend class PIMapIterator;
template<typename Key1, typename T1>
friend class PIMapIteratorReverse;
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIMap<Key1, T1> & v);
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIMap<Key1, T1> & v);
template <typename Key1, typename T1> friend class PIMapIterator;
public:
typedef T mapped_type;
typedef Key key_type;
typedef PIPair<Key, T> value_type;
//! \~english Constructs an empty map.
//! \~russian Создает пустой словарь.
inline PIMap() {}
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIMap(const PIMap<Key, T> & other): pim_content(other.pim_content), pim_index(other.pim_index) {}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIMap(PIMap<Key, T> && other): pim_content(std::move(other.pim_content)), pim_index(std::move(other.pim_index)) {}
//! \~english Contructs map from
//! [C++11 initializer list](https://en.cppreference.com/w/cpp/utility/initializer_list).
//! \~russian Создает словарь из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\details
//! \~\code
//! PIMap <int, PIString> m{{1, "a"}, {2, "b"}};
//! piCout << m; // {1: a, 2: b}
//! \endcode
inline PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
for (auto i: init_list) {
PIMap() {}
PIMap(const PIMap<Key, T> & other) {*this = other;}
PIMap(PIMap<Key, T> && other) : pim_content(std::move(other.pim_content)) {}
PIMap(std::initializer_list<std::pair<Key, T>> init_list) {
for (auto i: init_list)
insert(std::get<0>(i), std::get<1>(i));
}
}
virtual ~PIMap() {;}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIMap<Key, T> & operator=(const PIMap<Key, T> & other) {
PIMap<Key, T> & operator =(const PIMap<Key, T> & other) {
if (this == &other) return *this;
clear();
pim_content = other.pim_content;
pim_index = other.pim_index;
return *this;
}
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIMap<Key, T> & operator=(PIMap<Key, T> && other) {
PIMap<Key, T> & operator =(PIMap<Key, T> && other) {
swap(other);
return *this;
}
typedef T mapped_type;
typedef Key key_type;
typedef PIPair<Key, T> value_type;
class iterator {
friend class PIMap<Key, T>;
private:
iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
T & value() { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
inline PIPair<Key, T> operator*() const {
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator++() { ++pos; }
void operator++(int) { ++pos; }
void operator--() { --pos; }
void operator--(int) { --pos; }
bool operator==(const iterator & it) const { return (pos == it.pos); }
bool operator!=(const iterator & it) const { return (pos != it.pos); }
iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
inline PIPair<Key, T> operator *() const {return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));}
void operator ++() {++pos;}
void operator ++(int) {++pos;}
void operator --() {--pos;}
void operator --(int) {--pos;}
bool operator ==(const iterator & it) const {return (pos == it.pos);}
bool operator !=(const iterator & it) const {return (pos != it.pos);}
};
class reverse_iterator {
friend class PIMap<Key, T>;
private:
reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
reverse_iterator(): parent(nullptr), pos(0) {}
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
T & value() const { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
inline PIPair<Key, T> operator*() const {
return PIPair<Key, T>(const_cast<PIMap<Key, T> *>(parent)->_key(pos), const_cast<PIMap<Key, T> *>(parent)->_value(pos));
}
void operator++() { --pos; }
void operator++(int) { --pos; }
void operator--() { ++pos; }
void operator--(int) { ++pos; }
bool operator==(const reverse_iterator & it) const { return (pos == it.pos); }
bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); }
reverse_iterator(): parent(0), pos(0) {}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
inline PIPair<Key, T> operator *() const {return PIPair<Key, T>(const_cast<PIMap<Key, T> * >(parent)->_key(pos), const_cast<PIMap<Key, T> * >(parent)->_value(pos));}
void operator ++() {--pos;}
void operator ++(int) {--pos;}
void operator --() {++pos;}
void operator --(int) {++pos;}
bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
};
class const_iterator {
friend class PIMap<Key, T>;
private:
const_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
const_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); }
const Key & key() const { return const_cast<PIMap<Key, T> *>(parent)->_key(pos); }
const T & value() const { return const_cast<PIMap<Key, T> *>(parent)->_value(pos); }
void operator++() { ++pos; }
void operator++(int) { ++pos; }
void operator--() { --pos; }
void operator--(int) { --pos; }
bool operator==(const const_iterator & it) const { return (pos == it.pos); }
bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
const_iterator(): parent(0), pos(0) {}
const value_type operator *() const {return parent->_pair(pos);}
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
const Key & key() const {return const_cast<PIMap<Key, T> * >(parent)->_key(pos);}
const T & value() const {return const_cast<PIMap<Key, T> * >(parent)->_value(pos);}
void operator ++() {++pos;}
void operator ++(int) {++pos;}
void operator --() {--pos;}
void operator --(int) {--pos;}
bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
mutable value_type cval;
};
class const_reverse_iterator {
friend class PIMap<Key, T>;
private:
const_reverse_iterator(const PIMap<Key, T> * v, ssize_t p): parent(v), pos(p) {}
const PIMap<Key, T> * parent;
ssize_t pos;
public:
const_reverse_iterator(): parent(nullptr), pos(0) {}
const value_type operator*() const { return parent->_pair(pos); }
void operator++() { --pos; }
void operator++(int) { --pos; }
void operator--() { ++pos; }
void operator--(int) { ++pos; }
bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); }
bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); }
const_reverse_iterator(): parent(0), pos(0) {}
const value_type operator *() const {return parent->_pair(pos);}
const value_type* operator ->() const {cval = parent->_pair(pos); return &cval;}
void operator ++() {--pos;}
void operator ++(int) {--pos;}
void operator --() {++pos;}
void operator --(int) {++pos;}
bool operator ==(const const_reverse_iterator & it) const {return (pos == it.pos);}
bool operator !=(const const_reverse_iterator & it) const {return (pos != it.pos);}
mutable value_type cval;
};
iterator begin() {return iterator(this, 0);}
iterator end() {return iterator(this, size());}
const_iterator begin() const {return const_iterator(this, 0);}
const_iterator end() const {return const_iterator(this, size());}
const_iterator constBegin() const {return const_iterator(this, 0);}
const_iterator constEnd() const {return const_iterator(this, size());}
reverse_iterator rbegin() {return reverse_iterator(this, size() - 1);}
reverse_iterator rend() {return reverse_iterator(this, -1);}
const_reverse_iterator rbegin() const {return const_reverse_iterator(this, size() - 1);}
const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
const_reverse_iterator constRbegin() const {return const_reverse_iterator(this, size() - 1);}
const_reverse_iterator constRend() const {return const_reverse_iterator(this, -1);}
//! \~english Iterator to the first element.
//! \~russian Итератор на первый элемент.
inline iterator begin() { return iterator(this, 0); }
PIMapIterator<Key, T> makeIterator() const {return PIMapIterator<Key, T>(*this);}
PIMapIterator<Key, T> makeReverseIterator() const {return PIMapIterator<Key, T>(*this, true);}
//! \~english Iterator to the element following the last element.
//! \~russian Итератор на элемент, следующий за последним элементом.
inline iterator end() { return iterator(this, size()); }
size_t size() const {return pim_content.size();}
int size_s() const {return pim_content.size_s();}
size_t length() const {return pim_content.size();}
bool isEmpty() const {return (pim_content.size() == 0);}
inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, size()); }
//! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
inline reverse_iterator rbegin() { return reverse_iterator(this, size() - 1); }
//! \~english Returns a reverse iterator to the element.
//! following the last element of the reversed array.
//! \~russian Обратный итератор на элемент,
//! следующий за последним элементом.
inline reverse_iterator rend() { return reverse_iterator(this, -1); }
inline const_reverse_iterator rbegin() const { return const_reverse_iterator(this, size() - 1); }
inline const_reverse_iterator rend() const { return const_reverse_iterator(this, -1); }
//! \relatesalso PIMapIteratorConst
inline PIMapIteratorConst<Key, T> makeIterator() const { return PIMapIteratorConst<Key, T>(*this); }
//! \relatesalso PIMapIterator
inline PIMapIterator<Key, T> makeIterator() { return PIMapIterator<Key, T>(*this); }
//! \relatesalso PIMapIteratorConstReverse
inline PIMapIteratorConstReverse<Key, T> makeReverseIterator() const { return PIMapIteratorConstReverse<Key, T>(*this); }
//! \relatesalso PIMapIteratorReverse
inline PIMapIteratorReverse<Key, T> makeReverseIterator() { return PIMapIteratorReverse<Key, T>(*this); }
//! \~english Number of elements in the container.
//! \~russian Количество элементов массива.
//! \~\sa \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t size() const { return pim_content.size(); }
//! \~english Number of elements in the container as signed value.
//! \~russian Количество элементов массива в виде знакового числа.
//! \~\sa \a size(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline int size_s() const { return pim_content.size_s(); }
//! \~english Same as \a size().
//! \~russian Синоним \a size().
//! \~\sa \a size(), \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t length() const { return pim_content.size(); }
//! \~english Checks if the container has no elements.
//! \~russian Проверяет пуст ли массив.
//! \~\return
//! \~english **true** if the container is empty, **false** otherwise
//! \~russian **true** если массив пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isEmpty() const { return (pim_content.size() == 0); }
//! \~english Checks if the container has elements.
//! \~russian Проверяет не пуст ли массив.
//! \~\return
//! \~english **true** if the container is not empty, **false** otherwise
//! \~russian **true** если массив не пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isNotEmpty() const { return (pim_content.size() > 0); }
//! \~english Full access to element key `key`.
//! \~russian Полный доступ к элементу по ключу `key`.
//! \~\details
//! \~english If the map contains no item with key `key`,
//! the function inserts a default-constructed value into the map with key `key`,
//! and returns a reference to it.
//! \~russian Если элемента с таким ключом `key` не существует,
//! то он будет создан конструктором по умолчанию и добавлен в массив
//! по ключу `key`, а затем возвращена ссылка на этот новый элемент.
//! \~\code
//! PIMap <PIString, int> m;
//! m["огурец"] = 500;
//! piCout << m; // {огурец: 500}
//! m["лук"] = 25;
//! piCout << m; // {огурец: 500, лук: 25}
//! m["огурец"] = 350;
//! piCout << m; // {огурец: 350, лук: 25}
//! \endcode
//! \~\sa \a insert(), \a value(), \a key()
inline T & operator[](const Key & key) {
T & operator [](const Key & key) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) return _value(i);
pim_content.push_back(T());
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
return pim_content.back();
ssize_t i = _find(key, f);
if (!f) pim_content.insert(i, PIPair<Key, T>(key, T()));
return pim_content[i].second;
}
//! \~english Read only access to element by `key`.
//! \~russian Доступ исключительно на чтение к элементу по ключу `key`.
//! \~\note
//! \~english Element with key `key` must exists,
//! otherwise it will lead to undefined program behavior and memory errors.
//! \~russian Элемент по ключу `key` должен существовать,
//! иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
//! \~\sa \a operator[](), \a value(), \a key()
inline const T & at(const Key & key) const {
const T operator [](const Key & key) const {
bool f(false);
const ssize_t i = _find(key, f);
return _value(i);
ssize_t i = _find(key, f);
if (f) return pim_content[i].second;
return T();
}
const T at(const Key & key) const {return (*this)[key];}
//! \~english Remove element with key `key` from the array and return it.
//! \~russian Удаляет элемент с ключом `key` из массива и возвращает его.
inline T take(const Key & key, const T & default_ = T()) {
bool f(false);
const ssize_t i = _find(key, f);
if (!f) return default_;
const T ret = _value(i);
_remove(i);
return ret;
}
//! \~english Inserts all elements in array `other` to this array with overwrite.
//! \~russian Вставляет все элементы `other` этот массив с перезаписью.
inline PIMap<Key, T> & operator<<(const PIMap<Key, T> & other) {
PIMap<Key, T> & operator <<(const PIMap<Key, T> & other) {
#ifndef NDEBUG
if (&other == this) {
fprintf(stderr, "error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
printf("error with PIMap<%s, %s>::<<\n", __PIP_TYPENAME__(Key), __PIP_TYPENAME__(T));
}
#endif
assert(&other != this);
if (other.isEmpty()) return *this;
if (other.size() == 1) {
insert(other.pim_index[0].key, other.pim_content[0]);
return *this;
}
if (other.size() == 2) {
insert(other.pim_index[0].key, other.pim_content[0]);
insert(other.pim_index[1].key, other.pim_content[1]);
return *this;
}
for (int i = 0; i < other.pim_index.size_s(); ++i) {
insert(other.pim_index[i].key, other.pim_content[other.pim_index[i].index]);
}
// if (other.size() == 1) {insert(other.pim_index[0].key, other.pim_content[0]); return *this;}
// if (other.size() == 2) {insert(other.pim_index[0].key, other.pim_content[0]); insert(other.pim_index[1].key, other.pim_content[1]); return *this;}
for (int i = 0; i < other.pim_content.size_s(); ++i)
insert(other.pim_content[i].first, other.pim_content[i].second);
return *this;
}
//! \~english Compare operator with array `m`.
//! \~russian Оператор сравнения с массивом `m`.
inline bool operator==(const PIMap<Key, T> & m) const { return (pim_content == m.pim_content && pim_index == m.pim_index); }
bool operator ==(const PIMap<Key, T> & t) const {return (pim_content == t.pim_content);}
bool operator !=(const PIMap<Key, T> & t) const {return (pim_content != t.pim_content);}
bool contains(const Key & key) const {bool f(false); _find(key, f); return f;}
//! \~english Compare operator with array `m`.
//! \~russian Оператор сравнения с массивом `m`.
inline bool operator!=(const PIMap<Key, T> & m) const { return (pim_content != m.pim_content || pim_index != m.pim_index); }
PIMap<Key, T> & reserve(size_t new_size) {pim_content.reserve(new_size);return *this;}
//! \~english Tests if element with key `key` exists in the array.
//! \~russian Проверяет наличие элемента с ключом `key` в массиве.
inline bool contains(const Key & key) const {
bool f(false);
_find(key, f);
return f;
}
PIMap<Key, T> & removeOne(const Key & key) {bool f(false); ssize_t i = _find(key, f); if (f) _remove(i); return *this;}
PIMap<Key, T> & remove(const Key & key) {return removeOne(key);}
PIMap<Key, T> & erase(const Key & key) {return removeOne(key);}
PIMap<Key, T> & clear() {pim_content.clear(); return *this;}
//! \~english Tests if element with value `value` exists in the array.
//! \~russian Проверяет наличие элемента со значением `value` в массиве.
inline bool containsValue(const T & value) const { return pim_content.contains(value); }
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
inline PIMap<Key, T> & reserve(size_t new_size) {
pim_content.reserve(new_size);
pim_index.reserve(new_size);
return *this;
}
//! \~english Remove element with key `key` from the array.
//! \~russian Удаляет элемент с ключом `key` из массива.
inline PIMap<Key, T> & remove(const Key & key) {
bool f(false);
const ssize_t i = _find(key, f);
if (f) _remove(i);
return *this;
}
//! \~english Remove all elements in the array
//! passes the test implemented by the provided function `test`.
//! \~russian Удаляет все элементы, удовлетворяющие условию,
//! заданному в передаваемой функции `test`.
inline PIMap<Key, T> & removeWhere(std::function<bool(const Key & key, const T & value)> test) {
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
if (test(mi.key, pim_content[mi.index])) {
_remove(i);
--i;
}
}
return *this;
}
//! \~english Same as \a remove().
//! \~russian Синоним функции \a remove().
inline PIMap<Key, T> & erase(const Key & key) { return remove(key); }
//! \~english Clear array, remove all elements.
//! \~russian Очищает массив, удаляет все элементы.
//! \~\details
//! \~\note
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
inline PIMap<Key, T> & clear() {
pim_content.clear();
pim_index.clear();
return *this;
}
//! \~english Swaps array `v` other with this array.
//! \~russian Меняет местами массив `v` с этим массивом.
//! \~\details
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIMap<Key, T> & other) {
void swap(PIMap<Key, T> & other) {
pim_content.swap(other.pim_content);
pim_index.swap(other.pim_index);
}
//! \~english Inserts value `value` with key `key` in the array.
//! \~russian Вставляет значение `value` с ключом `key` в массив.
//! \~\details
//! \~english If an element with the key `key` already exists, it will be overwritten with the value `value`.
//! \~russian Если элемент с ключом `key` уже существует, то он будет перезаписан на значение `value`.
inline PIMap<Key, T> & insert(const Key & key, const T & value) {
PIMap<Key, T> & insert(const Key & key, const T & value) {
bool f(false);
const ssize_t i = _find(key, f);
ssize_t i = _find(key, f);
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
if (f) {
_value(i) = value;
pim_content[i].second = value;
} else {
pim_content.push_back(value);
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
pim_content.insert(i, PIPair<Key, T>(key, value));
}
return *this;
}
inline PIMap<Key, T> & insert(const Key & key, T && value) {
PIMap<Key, T> & insert(const Key & key, T && value) {
bool f(false);
const ssize_t i = _find(key, f);
ssize_t i = _find(key, f);
//piCout << "insert key=" << key << "found=" << f << "index=" << i << "value=" << value;
if (f) {
_value(i) = std::move(value);
pim_content[i].second = std::move(value);
} else {
pim_content.push_back(std::move(value));
pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
// pim_content.push_back(std::move(value));
// pim_index.insert(i, MapIndex(key, pim_content.size() - 1));
pim_content.insert(i, PIPair<Key, T>(key, std::move(value)));
}
return *this;
}
//! \~english Inserts value `pair` in the array.
//! \~russian Вставляет пару `pair` в массив.
//! \~\details
//! \~english The first element of the pair is the key, and the second is the value.
//! \~russian Первый элемент пары является ключом, а второй значением.
inline PIMap<Key, T> & insert(const PIPair<Key, T> & pair) {
const T value(const Key & key, const T & default_ = T()) const {
bool f(false);
const ssize_t i = _find(pair.first, f);
if (f) {
_value(i) = pair.second;
} else {
pim_content.push_back(pair.second);
pim_index.insert(i, MapIndex(pair.first, pim_content.size() - 1));
}
return *this;
}
inline PIMap<Key, T> & insert(PIPair<Key, T> && pair) {
bool f(false);
Key k(std::move(pair.first));
const ssize_t i = _find(k, f);
if (f) {
_value(i) = std::move(pair.second);
} else {
pim_content.push_back(std::move(pair.second));
pim_index.insert(i, MapIndex(k, pim_content.size() - 1));
}
return *this;
}
//! \~english Returns the value of the element by the key `key`
//! or `default_` if there is no such element.
//! \~russian Возвращает значение элемента по ключу `key`
//! или `default_` если такого элемента нет.
inline T value(const Key & key, const T & default_ = T()) const {
bool f(false);
const ssize_t i = _find(key, f);
ssize_t i = _find(key, f);
if (!f) return default_;
return _value(i);
}
//! \~english Returns an array of values of all elements
//! \~russian Возвращает массив значений всех эелметнов
inline PIVector<T> values() const { return pim_content; }
//! \~english Returns the key of the first element
//! whose value matches `value` or `default_` if there is no such element.
//! \~russian Возвращает ключ первого элемента, значение которого
//! совпадает с `value` или `default_` если такого элемента нет.
inline Key key(const T & value, const Key & default_ = Key()) const {
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
if (pim_content[mi.index] == value) {
return mi.key;
return pim_content[i].second;
}
PIVector<T> values() const {
PIVector<T> ret;
for (size_t i = 0; i < pim_content.size(); ++i) ret << pim_content[i].second;
return ret;
}
Key key(const T & value_, const Key & default_ = Key()) const {
for (int i = 0; i < pim_content.size_s(); ++i)
if (pim_content[i].second == value_)
return pim_content[i].first;
return default_;
}
//! \~english Returns an array of keys of all elements
//! \~russian Возвращает массив ключей всех элементов
inline PIVector<Key> keys() const {
PIVector<Key> keys() const {
PIVector<Key> ret;
ret.reserve(pim_index.size());
for (int i = 0; i < pim_index.size_s(); ++i) {
ret << pim_index[i].key;
}
for (size_t i = 0; i < pim_content.size(); ++i) ret << pim_content[i].first;
return ret;
}
//! \~english Execute function `void f(const Key & key, const T & value)` for every element in array.
//! \~russian Выполняет функцию `void f(const Key & key, const T & value)` для каждого элемента массива.
inline void forEach(std::function<void(const Key & key, const T & value)> f) const {
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
f(mi.key, pim_content[mi.index]);
}
}
//! \~english Сreates a new map PIMap<Key2, T2> populated with the results
//! of calling a provided function `PIPair<Key2, T2> f(const Key & key, const T & value)` on every element in the calling array.
//! \~russian Создаёт новый словарь PIMap<Key2, T2> с результатом вызова указанной функции
//! `PIPair<Key2, T2> f(const Key & key, const T & value)` для каждого элемента массива.
template<typename Key2, typename T2>
inline PIMap<Key2, T2> map(std::function<PIPair<Key2, T2>(const Key & key, const T & value)> f) const {
PIMap<Key2, T2> ret;
ret.reserve(size());
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
ret.insert(f(mi.key, pim_content[mi.index]));
}
return ret;
}
//! \~english Сreates a new array PIVector<ST> populated with the results
//! of calling a provided function `ST f(const Key & key, const T & value)` on every element in the calling array.
//! \~russian Создаёт новый массив PIVector<ST> с результатом вызова указанной функции
//! `ST f(const Key & key, const T & value)` для каждого элемента массива.
template<typename ST>
inline PIVector<ST> map(std::function<ST(const Key & key, const T & value)> f) const {
PIVector<ST> ret;
ret.reserve(size());
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
ret << f(mi.key, pim_content[mi.index]);
}
return ret;
}
//! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `bool test(const Key & key, const T & value)`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const Key & key, const T & value)`.
inline PIMap<Key, T> filter(std::function<bool(const Key & key, const T & value)> test) const {
PIMap<Key, T> ret;
for (int i = 0; i < pim_index.size_s(); ++i) {
const auto & mi(pim_index[i]);
const auto & v(pim_content[mi.index]);
if (test(mi.key, v)) {
ret.insert(mi.key, v);
}
}
return ret;
void dump() {
piCout << "PIMap" << size() << "entries" << PICoutManipulators::NewLine << "content:";
for (size_t i = 0; i < pim_content.size(); ++i)
piCout << PICoutManipulators::Tab << i << ":" << pim_content[i];
// piCout << "index:";
// for (size_t i = 0; i < pim_index.size(); ++i)
// piCout << PICoutManipulators::Tab << i << ":" << pim_index[i].key << "->" << pim_index[i].index;
}
protected:
struct MapIndex {
MapIndex(const Key & k = Key(), size_t i = 0): key(k), index(i) {}
MapIndex(Key && k, size_t i = 0): key(std::move(k)), index(i) {}
Key key;
size_t index;
bool operator==(const MapIndex & s) const { return key == s.key; }
bool operator!=(const MapIndex & s) const { return key != s.key; }
bool operator<(const MapIndex & s) const { return key < s.key; }
bool operator>(const MapIndex & s) const { return key > s.key; }
};
// struct MapIndex {
// MapIndex(Key k = Key(), size_t i = 0): key(k), index(i) {;}
// Key key;
// size_t index;
// bool operator ==(const MapIndex & s) const {return key == s.key;}
// bool operator !=(const MapIndex & s) const {return key != s.key;}
// bool operator <(const MapIndex & s) const {return key < s.key;}
// bool operator >(const MapIndex & s) const {return key > s.key;}
// };
// template <typename Key1, typename T1> friend PIByteArray & operator >>(PIByteArray & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
// template <typename Key1, typename T1> friend PIByteArray & operator <<(PIByteArray & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator>>(PIBinaryStream<P> & s, PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
template<typename P, typename Key1, typename T1>
friend PIBinaryStream<P> & operator<<(PIBinaryStream<P> & s, const PIDeque<typename PIMap<Key1, T1>::MapIndex> & v);
PIVector<T> pim_content;
PIDeque<MapIndex> pim_index;
private:
inline ssize_t _binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
ssize_t mid = 0;
ssize_t binarySearch(ssize_t first, ssize_t last, const Key & key, bool & found) const {
ssize_t mid;
while (first <= last) {
mid = (first + last) / 2;
if (key > pim_index[mid].key)
first = mid + 1;
else if (key < pim_index[mid].key)
last = mid - 1;
else {
found = true;
return mid;
}
if (key > pim_content[mid].first) first = mid + 1;
else if (key < pim_content[mid].first) last = mid - 1;
else {found = true; return mid;}
}
found = false;
return first;
}
inline ssize_t _find(const Key & k, bool & found) const {
if (pim_index.isEmpty()) {
ssize_t _find(const Key & k, bool & found) const {
if (pim_content.isEmpty()) {
found = false;
return 0;
}
return _binarySearch(0, pim_index.size_s() - 1, k, found);
return binarySearch(0, pim_content.size_s() - 1, k, found);
}
inline void _remove(ssize_t index) {
const size_t ci = pim_index[index].index, bi = pim_index.size() - 1;
pim_index.remove(index);
for (size_t i = 0; i < pim_index.size(); ++i) {
if (pim_index[i].index == bi) {
pim_index[i].index = ci;
break;
void _remove(ssize_t index) {
pim_content.remove(index);
}
const value_type _pair(ssize_t index) const {
if (index < 0 || index >= pim_content.size_s()) return value_type();
return pim_content[index];
}
piSwap<T>(pim_content[ci], pim_content.back());
pim_content.resize(pim_index.size());
}
Key & _key(ssize_t index) {return pim_content[index].first;}
T & _value(ssize_t index) {return pim_content[index].second;}
inline const value_type _pair(ssize_t index) const {
if (index < 0 || index >= pim_index.size_s()) return value_type();
const auto & mi(pim_index[index]);
return value_type(mi.key, pim_content[mi.index]);
}
inline Key & _key(ssize_t index) { return pim_index[index].key; }
inline const Key & _key(ssize_t index) const { return pim_index[index].key; }
inline T & _value(ssize_t index) { return pim_content[pim_index[index].index]; }
inline const T & _value(ssize_t index) const { return pim_content[pim_index[index].index]; }
PIDeque<PIPair<Key, T>> pim_content;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorConst
//! \brief
//! \~english Java-style iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial access keys and values in PIMap with read only permitions.
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря только для чтения.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeIterator();
//! while (it.next()) {
//! piCout << it.key() << it.value();
//! }
//! // 1 one
//! // 2 two
//! // 4 four
//! \endcode
template<typename Key, typename T>
class PIMapIteratorConst {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorConst(const PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline const T & value() const { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos < (m.size_s() - 1); }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
++pos;
return pos < m.size_s();
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = -1; }
private:
const MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorConstReverse
//! \brief
//! \~english Java-style reverse iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial reverse access keys and values in PIMap with read only permitions.
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке только для чтения.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeReverseIterator();
//! while (it.next()) {
//! piCout << it.key() << it.value();
//! }
//! // 4 four
//! // 2 two
//! // 1 one
//! \endcode
template<typename Key, typename T>
class PIMapIteratorConstReverse {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorConstReverse(const PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline const T & value() const { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos > 0; }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
--pos;
return pos >= 0;
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = m.size_s(); }
private:
const MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIterator
//! \brief
//! \~english Java-style iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial access keys and values in PIMap with write permitions.
//! Use constructor to create iterator, or use \a PIMap::makeIterator()
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря с доступом на запись.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeIterator();
//! while (it.next()) {
//! it.value().append("_!");
//! piCout << it.key() << it.value();
//! }
//! // 1 one_!
//! // 2 two_!
//! // 4 four_!
//! \endcode
template<typename Key, typename T>
template <typename Key, typename T>
class PIMapIterator {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIterator(PIMap<Key, T> & map): m(map), pos(-1) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline T & value() { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos < (m.size_s() - 1); }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
PIMapIterator(const PIMap<Key, T> & map, bool reverse = false): m(map), pos(-1), rev(reverse) {
if (rev) pos = m.size_s();
}
const Key & key() const {return const_cast<MapType & >(m)._key(pos);}
const T & value() const {return const_cast<MapType & >(m)._value(pos);}
T & valueRef() const {return const_cast<MapType & >(m)._value(pos);}
inline bool hasNext() const {
if (rev) {
return pos > 0;
} else {
return pos < (m.size_s() - 1);
}
return false;
}
inline bool next() {
if (rev) {
--pos;
return pos >= 0;
} else {
++pos;
return pos < m.size_s();
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = -1; }
private:
MapType & m;
ssize_t pos;
};
//! \addtogroup Containers
//! \{
//! \class PIMapIteratorReverse
//! \brief
//! \~english Java-style reverse iterator for \a PIMap.
//! \~russian Итератор Java стиля для \a PIMap в обратном порядке.
//! \~\}
//! \details
//! \~english
//! This class used to easy serial reverse access keys and values in PIMap with write permitions.
//! Use constructor to create iterator, or use \a PIMap::makeReverseIterator().
//! \~russian
//! Этот класс используется для удобного перебора ключей и значений всего словаря в обратном порядке с доступом на запись.
//! Можно использовать конструктор, в который передаётся словарь, или функцию словаря \a PIMap::makeReverseIterator().
//! \~
//! \code
//! PIMap<int, PIString> m;
//! m[1] = "one";
//! m[2] = "two";
//! m[4] = "four";
//! auto it = m.makeReverseIterator();
//! while (it.next()) {
//! it.value().append("_!");
//! piCout << it.key() << it.value();
//! }
//! // 4 four_!
//! // 2 two_!
//! // 1 one_!
//! \endcode
template<typename Key, typename T>
class PIMapIteratorReverse {
typedef PIMap<Key, T> MapType;
public:
inline PIMapIteratorReverse(PIMap<Key, T> & map): m(map), pos(m.size_s()) {}
//! \~english Returns current key.
//! \~russian Возвращает ключ текущего элемента.
//! \~\sa \a value()
inline const Key & key() const { return m._key(pos); }
//! \~english Returns current value.
//! \~russian Возвращает значение текущего элемента.
//! \~\sa \a key()
inline T & value() { return m._value(pos); }
//! \~english Returns true if iterator can jump to next entry
//! \~russian Возвращает true если итератор может перейти к следующему элементу.
//! \~\sa \a next()
inline bool hasNext() const { return pos > 0; }
//! \~english Jump to next entry and return true if new position is valid.
//! \~russian Переходит к следующему элементу и возвращает true если он существует.
//! \~\sa \a hasNext(), \a reset()
inline bool next() {
--pos;
return pos >= 0;
return false;
}
inline void reset() {
if (rev) {
pos = m.size_s();
} else {
pos = -1;
}
}
//! \~english Reset iterator to initial position.
//! \~russian Переходит на начало.
//! \~\sa \a next()
inline void reset() { pos = m.size_s(); }
private:
MapType & m;
const MapType & m;
ssize_t pos;
bool rev;
};
#ifdef PIP_STD_IOSTREAM
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename Key, typename Type>
inline std::ostream & operator<<(std::ostream & s, const PIMap<Key, Type> & v) {
inline std::ostream & operator <<(std::ostream & s, const PIMap<Key, Type> & v) {
s << "{";
bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) s << ", ";
if (!first)
s << ", ";
first = false;
s << i.key() << ": " << i.value();
s << i->first << ": " << i->second;
}
s << "}";
return s;
}
#endif
//! \relatesalso PICout
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename Key, typename Type>
inline PICout operator<<(PICout s, const PIMap<Key, Type> & v) {
inline PICout operator <<(PICout s, const PIMap<Key, Type> & v) {
s.space();
s.saveAndSetControls(0);
s.setControl(0, true);
s << "{";
bool first = true;
for (typename PIMap<Key, Type>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first) s << ", ";
if (!first)
s << ", ";
first = false;
s << i.key() << ": " << i.value();
s << i->first << ": " << i->second;
}
s << "}";
s.restoreControls();
s.restoreControl();
return s;
}
template<typename Key, typename Type>
inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {
f.swap(s);
}
template<typename Key, typename Type> inline void piSwap(PIMap<Key, Type> & f, PIMap<Key, Type> & s) {f.swap(s);}
#endif // PIMAP_H

View File

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

View File

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

View File

@@ -2,7 +2,7 @@
* \brief Set container
*
* This file declare PISet
*/
*/
/*
PIP - Platform Independent Primitives
Set container
@@ -34,124 +34,30 @@
* set with \a operator[] or with function \a find(). These function
* has logarithmic complexity.
*/
template<typename T>
template <typename T>
class PISet: public PIMap<T, uchar> {
typedef PIMap<T, uchar> _CSet;
public:
//! Contructs an empty set
PISet() {}
virtual ~PISet() {;}
//! Contructs set with one element "value"
explicit PISet(const T & value) { _CSet::insert(value, 0); }
PISet(const T & value) {_CSet::insert(value, 0);}
//! Contructs set with elements "v0" and "v1"
PISet(const T & v0, const T & v1) {
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
}
PISet(const T & v0, const T & v1) {_CSet::insert(v0, 0); _CSet::insert(v1, 0);}
//! Contructs set with elements "v0", "v1" and "v2"
PISet(const T & v0, const T & v1, const T & v2) {
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
_CSet::insert(v2, 0);
}
PISet(const T & v0, const T & v1, const T & v2) {_CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0);}
//! Contructs set with elements "v0", "v1", "v2" and "v3"
PISet(const T & v0, const T & v1, const T & v2, const T & v3) {
_CSet::insert(v0, 0);
_CSet::insert(v1, 0);
_CSet::insert(v2, 0);
_CSet::insert(v3, 0);
}
class const_iterator {
friend class PISet<T>;
private:
inline const_iterator(const PISet<T> * v, ssize_t p): parent(v), pos(p) {}
const PISet<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_iterator(): parent(0), pos(0) {}
inline const T & operator*() const { return parent->pim_index[pos].key; }
inline const T & operator->() const { return parent->pim_index[pos].key; }
inline const_iterator & operator++() {
++pos;
return *this;
}
inline const_iterator operator++(int) {
const auto tmp = *this;
++*this;
return tmp;
}
inline const_iterator & operator--() {
--pos;
return *this;
}
inline const_iterator operator--(int) {
const auto tmp = *this;
--*this;
return tmp;
}
inline const_iterator & operator+=(const const_iterator & it) {
pos += it.pos;
return *this;
}
inline const_iterator & operator+=(size_t p) {
pos += p;
return *this;
}
inline const_iterator & operator-=(const const_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_iterator & operator-=(size_t p) {
pos -= p;
return *this;
}
friend inline const_iterator operator-(size_t p, const const_iterator & it) { return it - p; }
friend inline const_iterator operator-(const const_iterator & it, size_t p) {
auto tmp = it;
tmp -= p;
return tmp;
}
friend inline std::ptrdiff_t operator-(const const_iterator & it1, const const_iterator & it2) { return it1.pos - it2.pos; }
friend inline const_iterator operator+(size_t p, const const_iterator & it) { return it + p; }
friend inline const_iterator operator+(const const_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const const_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; }
};
inline const_iterator begin() const { return const_iterator(this, 0); }
inline const_iterator end() const { return const_iterator(this, _CSet::size()); }
PISet(const T & v0, const T & v1, const T & v2, const T & v3) {_CSet::insert(v0, 0); _CSet::insert(v1, 0); _CSet::insert(v2, 0); _CSet::insert(v3, 0);}
//! Contructs set from vector of elements
explicit PISet(const PIVector<T> & values) {
PISet(const PIVector<T> & values) {
if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0);
@@ -159,7 +65,7 @@ public:
}
//! Contructs set from deque of elements
explicit PISet(const PIDeque<T> & values) {
PISet(const PIDeque<T> & values) {
if (values.isEmpty()) return;
for (int i = 0; i < values.size_s(); ++i) {
_CSet::insert(values[i], 0);
@@ -168,128 +74,88 @@ public:
typedef T key_type;
PISet<T> & operator<<(const T & t) {
_CSet::insert(t, 0);
return *this;
}
PISet<T> & operator<<(T && t) {
_CSet::insert(std::move(t), 0);
return *this;
}
PISet<T> & operator<<(const PISet<T> & other) {
(*(_CSet *)this) << *((_CSet *)&other);
return *this;
}
//! \~english Tests if element `key` exists in the set.
//! \~russian Проверяет наличие элемента `key` в массиве.
inline bool contains(const T & t) const { return _CSet::contains(t); }
PISet<T> & operator <<(const T & t) {_CSet::insert(t, 0); return *this;}
PISet<T> & operator <<(T && t) {_CSet::insert(std::move(t), 0); return *this;}
PISet<T> & operator <<(const PISet<T> & other) {(*(_CSet*)this) << *((_CSet*)&other); return *this;}
//! Returns if element "t" exists in this set
bool operator[](const T & t) const { return _CSet::contains(t); }
bool operator [](const T & t) const {return _CSet::contains(t);}
//! Returns if element "t" exists in this set
PISet<T> & remove(const T & t) {
_CSet::remove(t);
return *this;
}
PISet<T> & remove(const T & t) {_CSet::remove(t); return *this;}
//! Unite set with "v"
PISet<T> & unite(const PISet<T> & v) {
for (const auto & i: v)
_CSet::insert(i, 0);
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
_CSet::insert(i->first, 0);
return *this;
}
//! Subtract set with "v"
PISet<T> & subtract(const PISet<T> & v) {
for (const auto & i: v)
_CSet::remove(i);
for (typename PIMap<T, uchar>::const_iterator i = v.begin(); i != v.end(); ++i)
_CSet::remove(i->first);
return *this;
}
//! Intersect set with "v"
PISet<T> & intersect(const PISet<T> & v) {
_CSet::removeWhere([&v](const T & k, uchar) { return !v.contains(k); });
for (typename _CSet::iterator i = _CSet::begin(); i != _CSet::end(); ++i)
if (!v.contains(i.key())) {
_CSet::remove(i.key());
--i;
}
return *this;
}
//! Unite set with "v"
PISet<T> & operator+=(const PISet<T> & v) { return unite(v); }
PISet<T> & operator +=(const PISet<T> & v) {return unite(v);}
//! Unite set with "v"
PISet<T> & operator|=(const PISet<T> & v) { return unite(v); }
PISet<T> & operator |=(const PISet<T> & v) {return unite(v);}
//! Subtract set with "v"
PISet<T> & operator-=(const PISet<T> & v) { return subtract(v); }
PISet<T> & operator -=(const PISet<T> & v) {return subtract(v);}
//! Intersect set with "v"
PISet<T> & operator&=(const PISet<T> & v) { return intersect(v); }
PISet<T> & operator &=(const PISet<T> & v) {return intersect(v);}
//! Returns content of set as PIVector
PIVector<T> toVector() const {
PIVector<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
PIVector<T> toVector() const {PIVector<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
//! Returns content of set as PIDeque
PIDeque<T> toDeque() const {
PIDeque<T> ret;
for (const auto & i: *this)
ret << i;
return ret;
}
PIDeque<T> toDeque() const {PIDeque<T> ret; for (typename _CSet::const_iterator i = _CSet::begin(); i != _CSet::end(); ++i) ret << (*i).first; return ret;}
};
//! \relatesalso PISet \brief Returns unite of two sets
template<typename T>
PISet<T> operator+(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
template <typename T> PISet<T> operator +(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
//! \relatesalso PISet \brief Returns subtraction of two sets
template<typename T>
PISet<T> operator-(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.subtract(v1);
return ret;
}
template <typename T> PISet<T> operator -(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.subtract(v1); return ret;}
//! \relatesalso PISet \brief Returns unite of two sets
template<typename T>
PISet<T> operator|(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.unite(v1);
return ret;
}
template <typename T> PISet<T> operator |(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.unite(v1); return ret;}
//! \relatesalso PISet \brief Returns intersetion of two sets
template<typename T>
PISet<T> operator&(const PISet<T> & v0, const PISet<T> & v1) {
PISet<T> ret(v0);
ret.intersect(v1);
return ret;
}
template <typename T> PISet<T> operator &(const PISet<T> & v0, const PISet<T> & v1) {PISet<T> ret(v0); ret.intersect(v1); return ret;}
template<typename Type>
inline PICout operator<<(PICout s, const PISet<Type> & v) {
inline PICout operator <<(PICout s, const PISet<Type> & v) {
s.space();
s.saveAndSetControls(0);
s.setControl(0, true);
s << "{";
bool first = true;
for (const auto & i: v) {
if (!first) s << ", ";
for (typename PIMap<Type, uchar>::const_iterator i = v.begin(); i != v.end(); ++i) {
if (!first)
s << ", ";
first = false;
s << i;
s << i->first;
}
s << "}";
s.restoreControls();
s.restoreControl();
return s;
}

View File

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

View File

@@ -74,9 +74,9 @@
//! if the number of elements is known beforehand.
//!
//! The complexity (efficiency) of common operations on PIVector is as follows:
//! - Random access - constant O(1)
//! - Insertion or removal of elements at the end - amortized constant O(1)
//! - Insertion or removal of elements - linear in the distance to the end of the array O(n)
//! - 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
//! Элементы хранятся непрерывно, а значит доступны не только через итераторы,
@@ -109,31 +109,33 @@
//! если количество элементов известно заранее.
//!
//! Сложность (эффективность) обычных операций над PIVector следующая:
//! - Произвольный доступ — постоянная O(1)
//! - Вставка и удаление элементов в конце — амортизированная постоянная O(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива O(n)
//! - Произвольный доступ — постоянная 𝓞(1)
//! - Вставка и удаление элементов в конце — амортизированная постоянная 𝓞(1)
//! - Вставка и удаление элементов — линейная по расстоянию до конца массива 𝓞(n)
//!
//! \~\sa \a PIDeque, \a PIMap
template<typename T>
template <typename T>
class PIVector {
public:
typedef bool (*CompareFunc)(const T &, const T &);
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 T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
//! \~english Constructs an empty array.
//! \~russian Создает пустой массив.
inline PIVector() { PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T)) }
inline PIVector(): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
}
//! \~english Contructs array from raw `data`.
//! This constructor reserve `size` and copy from `data` pointer.
//! \~russian Создает массив из указателя на данные `data` и размер `size`.
//! То есть выделяет память для `size` элементов и копирует данные из указателя `data`.
inline PIVector(const T * data, size_t size) {
inline PIVector(const T * data, size_t size): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(size);
newT(piv_data, data, piv_size);
@@ -141,7 +143,7 @@ public:
//! \~english Copy constructor.
//! \~russian Копирующий конструктор.
inline PIVector(const PIVector<T> & v) {
inline PIVector(const PIVector<T> & v): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size);
@@ -156,7 +158,7 @@ public:
//! PIVector <int> v{1,2,3};
//! piCout << v; // {1, 2, 3}
//! \endcode
inline PIVector(std::initializer_list<T> init_list) {
inline PIVector(std::initializer_list<T> init_list): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
alloc(init_list.size());
newT(piv_data, init_list.begin(), init_list.size());
@@ -164,9 +166,9 @@ public:
//! \~english Contructs array with size `size` filled elements `e`.
//! \~russian Создает массив из `size` элементов заполненных `e`.
inline explicit PIVector(size_t size, const T & e = T()) {
inline PIVector(size_t size, const T & e = T()): piv_data(0), piv_size(0), piv_rsize(0) {
PIINTROSPECTION_CONTAINER_NEW(T, sizeof(T))
expand(size, e);
resize(size, e);
}
//! \~english Contructs array with size `size` and elements created by function `f(size_t i)`.
@@ -182,33 +184,32 @@ public:
//! 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) {
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))
expand(size, f);
resize(size, f);
}
//! \~english Move constructor.
//! \~russian Перемещающий конструктор.
inline PIVector(PIVector<T> && v) {
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))
piv_data = v.piv_data;
piv_size = v.piv_size;
piv_rsize = v.piv_rsize;
v._reset();
}
inline ~PIVector() {
inline virtual ~PIVector() {
PIINTROSPECTION_CONTAINER_DELETE(T)
PIINTROSPECTION_CONTAINER_FREE(T, (piv_rsize))
deleteT(piv_data, piv_size);
dealloc();
_reset();
}
//! \~english Assign operator.
//! \~russian Оператор присваивания.
inline PIVector<T> & operator=(const PIVector<T> & v) {
inline PIVector<T> & operator =(const PIVector<T> & v) {
if (this == &v) return *this;
clear();
deleteT(piv_data, piv_size);
alloc(v.piv_size);
newT(piv_data, v.piv_data, piv_size);
return *this;
@@ -216,330 +217,360 @@ public:
//! \~english Assign move operator.
//! \~russian Оператор перемещающего присваивания.
inline PIVector<T> & operator=(PIVector<T> && v) {
inline PIVector<T> & operator =(PIVector<T> && v) {
swap(v);
return *this;
}
class iterator {
friend class PIVector<T>;
private:
inline iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline iterator(): parent(0), pos(0) {}
inline T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline iterator & operator++() {
inline iterator & operator ++() {
++pos;
return *this;
}
inline iterator operator++(int) {
const auto tmp = *this;
inline iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline iterator & operator--() {
inline iterator & operator --() {
--pos;
return *this;
}
inline iterator operator--(int) {
const auto tmp = *this;
inline iterator operator --(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline iterator & operator+=(const iterator & it) {
inline iterator & operator +=(const iterator & it) {
pos += it.pos;
return *this;
}
inline iterator & operator+=(size_t p) {
inline iterator & operator +=(size_t p) {
pos += p;
return *this;
}
inline iterator & operator-=(const iterator & it) {
inline iterator & operator -=(const iterator & it) {
pos -= it.pos;
return *this;
}
inline iterator & operator-=(size_t p) {
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) {
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 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) {
friend inline iterator operator +(size_t p, const iterator & it) {return it + p;}
friend inline iterator operator +(const iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const iterator & it1, const iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const iterator & it1, const iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const iterator & it1, const iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const iterator & it1, const iterator & it2) { return it1.pos >= it2.pos; }
inline bool operator ==(const iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const iterator & it1, const iterator & it2) {
return it1.pos < it2.pos;
}
friend inline bool operator <=(const iterator & it1, const iterator & it2) {
return it1.pos <= it2.pos;
}
friend inline bool operator >(const iterator & it1, const iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const iterator & it1, const iterator & it2) {
return it1.pos >= it2.pos;
}
};
class const_iterator {
friend class PIVector<T>;
private:
inline const_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
const PIVector<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_iterator(): parent(0), pos(0) {}
inline const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline const T & operator *() const {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline const_iterator & operator++() {
inline const_iterator & operator ++() {
++pos;
return *this;
}
inline const_iterator operator++(int) {
const auto tmp = *this;
inline const_iterator operator ++(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline const_iterator & operator--() {
inline const_iterator & operator --() {
--pos;
return *this;
}
inline const_iterator operator--(int) {
const auto tmp = *this;
inline const_iterator operator --(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline const_iterator & operator+=(const const_iterator & it) {
inline const_iterator & operator +=(const const_iterator & it) {
pos += it.pos;
return *this;
}
inline const_iterator & operator+=(size_t p) {
inline const_iterator & operator +=(size_t p) {
pos += p;
return *this;
}
inline const_iterator & operator-=(const const_iterator & it) {
inline const_iterator & operator -=(const const_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_iterator & operator-=(size_t p) {
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) {
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 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) {
friend inline const_iterator operator +(size_t p, const const_iterator & it) {return it + p;}
friend inline const_iterator operator +(const const_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const const_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const const_iterator & it1, const const_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const const_iterator & it1, const const_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const const_iterator & it1, const const_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const const_iterator & it1, const const_iterator & it2) { return it1.pos >= it2.pos; }
inline bool operator ==(const const_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const const_iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const const_iterator & it1, const const_iterator & it2) {
return it1.pos < it2.pos;
}
friend inline bool operator <=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos <= it2.pos;
}
friend inline bool operator >(const const_iterator & it1, const const_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const const_iterator & it1, const const_iterator & it2) {
return it1.pos >= it2.pos;
}
};
class reverse_iterator {
friend class PIVector<T>;
private:
inline reverse_iterator(PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
PIVector<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline reverse_iterator(): parent(0), pos(0) {}
inline T & operator*() { return (*parent)[pos]; }
inline const T & operator*() const { return (*parent)[pos]; }
inline T & operator->() { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline T & operator *() {return (*parent)[pos];}
inline const T & operator *() const {return (*parent)[pos];}
inline T & operator ->() {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline reverse_iterator & operator++() {
inline reverse_iterator & operator ++() {
--pos;
return *this;
}
inline reverse_iterator operator++(int) {
const auto tmp = *this;
inline reverse_iterator operator ++(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline reverse_iterator & operator--() {
inline reverse_iterator & operator --() {
++pos;
return *this;
}
inline reverse_iterator operator--(int) {
const auto tmp = *this;
inline reverse_iterator operator --(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline reverse_iterator & operator+=(const reverse_iterator & it) {
inline reverse_iterator & operator +=(const reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline reverse_iterator & operator+=(size_t p) {
inline reverse_iterator & operator +=(size_t p) {
pos -= p;
return *this;
}
inline reverse_iterator & operator-=(const reverse_iterator & it) {
inline reverse_iterator & operator -=(const reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline reverse_iterator & operator-=(size_t p) {
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) {
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 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) {
friend inline reverse_iterator operator +(size_t p, const reverse_iterator & it) {return it + p;}
friend inline reverse_iterator operator +(const reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const reverse_iterator & it1, const reverse_iterator & it2) { return it1.pos >= it2.pos; }
inline bool operator ==(const reverse_iterator & it) const {return (pos == it.pos);}
inline bool operator !=(const reverse_iterator & it) const {return (pos != it.pos);}
friend inline bool operator <(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos < it2.pos;
}
friend inline bool operator <=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos <= it2.pos;
}
friend inline bool operator >(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos > it2.pos;
}
friend inline bool operator >=(const reverse_iterator & it1, const reverse_iterator & it2) {
return it1.pos >= it2.pos;
}
};
class const_reverse_iterator {
friend class PIVector<T>;
private:
inline const_reverse_iterator(const PIVector<T> * v, ssize_t p): parent(v), pos(p) {}
const PIVector<T> * parent;
ssize_t pos;
public:
typedef T value_type;
typedef T * pointer;
typedef T & reference;
typedef T* pointer;
typedef T& reference;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
inline const_reverse_iterator(): parent(0), pos(0) {}
inline const T & operator*() const { return (*parent)[pos]; }
inline const T & operator->() const { return (*parent)[pos]; }
inline const T & operator *() const {return (*parent)[pos];}
inline const T & operator ->() const {return (*parent)[pos];}
inline const_reverse_iterator & operator++() {
inline const_reverse_iterator & operator ++() {
--pos;
return *this;
}
inline const_reverse_iterator operator++(int) {
const auto tmp = *this;
inline const_reverse_iterator operator ++(int) {
auto tmp = *this;
--*this;
return tmp;
}
inline const_reverse_iterator & operator--() {
inline const_reverse_iterator & operator --() {
++pos;
return *this;
}
inline const_reverse_iterator operator--(int) {
const auto tmp = *this;
inline const_reverse_iterator operator --(int) {
auto tmp = *this;
++*this;
return tmp;
}
inline const_reverse_iterator & operator+=(const const_reverse_iterator & it) {
inline const_reverse_iterator & operator +=(const const_reverse_iterator & it) {
pos -= it.pos;
return *this;
}
inline const_reverse_iterator & operator+=(size_t p) {
inline const_reverse_iterator & operator +=(size_t p) {
pos -= p;
return *this;
}
inline const_reverse_iterator & operator-=(const const_reverse_iterator & it) {
inline const_reverse_iterator & operator -=(const const_reverse_iterator & it) {
pos += it.pos;
return *this;
}
inline const_reverse_iterator & operator-=(size_t p) {
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) {
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) {
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) {
friend inline const_reverse_iterator operator +(size_t p, const const_reverse_iterator & it) {return it + p;}
friend inline const_reverse_iterator operator +(const const_reverse_iterator & it, size_t p) {
auto tmp = it;
tmp += p;
return tmp;
}
inline bool operator==(const const_reverse_iterator & it) const { return (pos == it.pos); }
inline bool operator!=(const const_reverse_iterator & it) const { return (pos != it.pos); }
friend inline bool operator<(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos < it2.pos; }
friend inline bool operator<=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos <= it2.pos; }
friend inline bool operator>(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos > it2.pos; }
friend inline bool operator>=(const const_reverse_iterator & it1, const const_reverse_iterator & it2) { return it1.pos >= it2.pos; }
inline 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.
@@ -550,7 +581,7 @@ public:
//! \~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 Итератор на элемент, следующий за последним элементом.
@@ -562,10 +593,10 @@ public:
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\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 end() const { return const_iterator(this, piv_size); }
inline const_iterator begin() const {return const_iterator(this, 0);}
inline const_iterator end() const {return const_iterator(this, piv_size);}
//! \~english Returns a reverse iterator to the first element of the reversed array.
//! \~russian Обратный итератор на первый элемент.
@@ -578,7 +609,7 @@ public:
//! Если массив пустой, то совпадает с итератором \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.
@@ -593,49 +624,49 @@ public:
//! попытка доступа к нему приведёт к выходу за разрешенную память.
//! \~\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 rend() const { return const_reverse_iterator(this, -1); }
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(this, piv_size - 1);}
inline const_reverse_iterator rend() const {return const_reverse_iterator(this, -1);}
//! \~english Number of elements in the container.
//! \~russian Количество элементов массива.
//! \~\sa \a size_s(), \a capacity(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline size_t size() const { return piv_size; }
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 Количество элементов, для которого сейчас выделена память массивом.
//! \~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 Проверяет пуст ли массив.
//! \~russian Проверяет пуст ли контейнер.
//! \~\return
//! \~english **true** if the container is empty, **false** otherwise
//! \~russian **true** если массив пуст, **false** иначе.
//! \~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);}
//! \~english Checks if the container has elements.
//! \~russian Проверяет не пуст ли массив.
//! \~russian Проверяет не пуст ли контейнер.
//! \~\return
//! \~english **true** if the container is not empty, **false** otherwise
//! \~russian **true** если массив не пуст, **false** иначе.
//! \~russian **true** если контейнер не пуст, **false** иначе.
//! \~\sa \a size(), \a size_s(), \a isEmpty(), \a isNotEmpty(), \a resize(), \a reserve()
inline bool isNotEmpty() const { return (piv_size > 0); }
inline bool isNotEmpty() const {return (piv_size > 0);}
//! \~english Tests whether at least one element in the array
//! passes the test implemented by the provided function `test`.
@@ -703,8 +734,8 @@ public:
//! 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]; }
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`.
@@ -715,36 +746,7 @@ public:
//! \~russian Индекс элемента считается от `0`.
//! Индекс элемента должен лежать в пределах от `0` до `size()-1`.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline const T & at(size_t index) const { return piv_data[index]; }
//! \~english Returns the first element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает первый элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a indexWhere()
inline const T & atWhere(std::function<bool(const T & e)> test, ssize_t start = 0, const T & def = T()) const {
const ssize_t i = indexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
//! \~english Returns the last element of the array that
//! passes the test implemented by the provided function `test`
//! or `def` if there is no such element.
//! \~russian Возвращает последний элемент массива, проходящего по условию,
//! заданному в передаваемой функции `test`, или `def` если такого элемента нет.
//! \~\sa \a lastIndexWhere()
inline const T & lastAtWhere(std::function<bool(const T & e)> test, ssize_t start = -1, const T & def = T()) const {
const ssize_t i = lastIndexWhere(test, start);
if (i < 0)
return def;
else
return at(i);
}
inline const T & at(size_t index) const {return piv_data[index];}
//! \~english Last element.
//! \~russian Последний элемент массива.
@@ -755,8 +757,8 @@ public:
//! \~russian Возвращает ссылку на последний элемент в массиве.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline T & back() { return piv_data[piv_size - 1]; }
inline const T & back() const { return piv_data[piv_size - 1]; }
inline T & back() {return piv_data[piv_size - 1];}
inline const T & back() const {return piv_data[piv_size - 1];}
//! \~english Last element.
//! \~russian Первый элемент массива.
@@ -767,12 +769,12 @@ public:
//! \~russian Возвращает ссылку на пенрвый элемент в массиве.
//! Эта функция предполагает, что массив не пустой.
//! Иначе это приведёт к неопределённому поведению программы и ошибкам памяти.
inline T & front() { return piv_data[0]; }
inline const T & front() const { return piv_data[0]; }
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 {
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;
@@ -782,7 +784,7 @@ public:
//! \~english Compare operator with array `v`.
//! \~russian Оператор сравнения с массивом `v`.
inline bool operator!=(const PIVector<T> & v) const { return !(*this == v); }
inline bool operator !=(const PIVector<T> & v) const {return !(*this == v);}
//! \~english Tests if element `e` exists in the array.
//! \~russian Проверяет наличие элемента `e` в массиве.
@@ -800,7 +802,7 @@ public:
//! возвращается **false**, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<int> v{1, 2, 3, 4};
@@ -827,33 +829,6 @@ public:
return false;
}
//! \~english Tests if all elements of `v` exists in the array.
//! \~russian Проверяет наличие всех элементов `v` в массиве.
//! \~\details
//! \~\code
//! PIVector<int> v{1, 2, 3, 4};
//! piCout << v.contains({1,4}); // true
//! piCout << v.contains({1,5}); // false
//! \endcode
//! \~\sa \a every(), \a any(), \a entries(), \a forEach()
inline bool contains(const PIVector<T> & v, ssize_t start = 0) const {
if (start < 0) {
start = piv_size + start;
if (start < 0) start = 0;
}
for (const T & e: v) {
bool c = false;
for (size_t i = start; i < piv_size; ++i) {
if (e == piv_data[i]) {
c = true;
break;
}
}
if (!c) return false;
}
return true;
}
//! \~english Count elements equal `e` in the array.
//! \~russian Подсчитывает количество элементов, совпадающих с элементом `e` в массиве.
//! \~\details
@@ -870,7 +845,7 @@ public:
//! возвращается 0, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<int> v{2, 2, 4, 2, 6};
@@ -910,7 +885,7 @@ public:
//! возвращается 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 {
@@ -943,7 +918,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<int> v{2, 5, 9};
@@ -984,7 +959,7 @@ public:
//! возвращается `-1`, что означает, что массив даже не просматривается.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Если рассчитанный индекс все равно оказывается меньше 0, просматривается весь массив.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу (слева на право).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу.
//! Значение по умолчанию равно 0, что означает, что просматривается весь массив.
//! \~\code
//! PIVector<PIString> v{"do", "re", "mi", "re"};
@@ -1024,7 +999,7 @@ public:
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
@@ -1067,7 +1042,7 @@ public:
//! c которого начинать поиск в обратном направлении.
//! Если индекс больше или равен длине массива, просматривается весь массив.
//! Если индекс является отрицательным числом, он трактуется как смещение с конца массива.
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу (справа на лево).
//! Обратите внимание: если индекс отрицателен, массив всё равно просматривается от конца к началу.
//! Если рассчитанный индекс оказывается меньше 0, массив даже не просматривается.
//! Значение по умолчанию равно `-1`, что равно индексу последнего элемента
//! и означает, что просматривается весь массив.
@@ -1094,7 +1069,7 @@ public:
//! 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 Указатель на память массива только для чтения.
@@ -1113,7 +1088,7 @@ public:
//! 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 Создает подмассив, то есть кусок из текущего массива.
@@ -1134,7 +1109,7 @@ public:
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);
return PIVector(&(piv_data[index]), count);
}
//! \~english Clear array, remove all elements.
@@ -1144,13 +1119,16 @@ public:
//! \~english Reserved memory will not be released.
//! \~russian Зарезервированная память не освободится.
//! \~\sa \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & clear() {
deleteT(piv_data, piv_size);
piv_size = 0;
resize(0);
return *this;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & clear() {
PIINTROSPECTION_CONTAINER_UNUSED(T, piv_size)
piv_size = 0;
@@ -1196,17 +1174,21 @@ public:
//! \~english Same as \a fill().
//! \~russian Тоже самое что и \a fill().
//! \~\sa \a fill(), \a resize()
inline PIVector<T> & assign(const T & e = T()) { return fill(e); }
inline PIVector<T> & assign(const T & e = T()) {return fill(e);}
//! \~english First does `resize(new_size)` then `fill(e)`.
//! \~russian Сначала делает `resize(new_size)`, затем `fill(e)`.
//! \~\sa \a fill(), \a resize()
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & assign(size_t new_size, const T & f) {
resize(new_size);
return fill(f);
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & assign(size_t new_size, const T & f) {
_resizeRaw(new_size);
return fill(f);
@@ -1225,10 +1207,17 @@ public:
//! \~\sa \a size(), \a clear()
inline PIVector<T> & resize(size_t new_size, const T & e = T()) {
if (new_size < piv_size) {
deleteT(piv_data + new_size, piv_size - new_size);
T * de = &(piv_data[new_size]);
deleteT(de, piv_size - new_size);
piv_size = new_size;
} else if (new_size > piv_size) {
expand(new_size, e);
}
if (new_size > piv_size) {
size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, e);
}
}
return *this;
}
@@ -1246,29 +1235,38 @@ public:
//! \~\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) {
deleteT(piv_data + new_size, piv_size - new_size);
T * de = &(piv_data[new_size]);
deleteT(de, piv_size - new_size);
piv_size = new_size;
} else if (new_size > piv_size) {
expand(new_size, f);
}
if (new_size > piv_size) {
size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size-os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f(i));
}
}
return *this;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline PIVector<T> & _resizeRaw(size_t new_size) {
#if defined(PIP_INTROSPECTION) && !defined(PIP_FORCE_NO_PIINTROSPECTION)
if (new_size > piv_size) {
PIINTROSPECTION_CONTAINER_USED(T, (new_size - piv_size));
PIINTROSPECTION_CONTAINER_USED(T, (new_size-piv_size));
}
if (new_size < piv_size) {
PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size - new_size));
PIINTROSPECTION_CONTAINER_UNUSED(T, (piv_size-new_size));
}
#endif
alloc(new_size);
return *this;
}
inline void _copyRaw(T * dst, const T * src, size_t size) { newT(dst, src, size); }
inline void _copyRaw(T * dst, const T * src, size_t size) {
newT(dst, src, size);
}
//! \~english Attempts to allocate memory for at least `new_size` elements.
//! \~russian Резервируется память под как минимум `new_size` элементов.
@@ -1286,7 +1284,7 @@ public:
//! \~\sa \a size(), \a capacity(), \a resize()
inline PIVector<T> & reserve(size_t new_size) {
if (new_size <= piv_rsize) return *this;
const size_t os = piv_size;
size_t os = piv_size;
alloc(new_size);
piv_size = os;
return *this;
@@ -1306,8 +1304,8 @@ public:
inline PIVector<T> & insert(size_t index, const T & e = T()) {
alloc(piv_size + 1);
if (index < piv_size - 1) {
const size_t os = piv_size - index - 1;
memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
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, e);
@@ -1323,8 +1321,8 @@ public:
inline PIVector<T> & insert(size_t index, T && e) {
alloc(piv_size + 1);
if (index < piv_size - 1) {
const size_t os = piv_size - index - 1;
memmove(reinterpret_cast<void *>(piv_data + index + 1), reinterpret_cast<const void *>(piv_data + index), os * sizeof(T));
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));
@@ -1341,16 +1339,14 @@ public:
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
fprintf(stderr, "error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
printf("error with PIVector<%s>::insert\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const ssize_t os = piv_size - index;
ssize_t os = piv_size - index;
alloc(piv_size + v.piv_size);
if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index + v.piv_size),
reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T));
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;
@@ -1367,13 +1363,10 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append(), \a prepend(), \a remove()
inline PIVector<T> & insert(size_t index, std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const ssize_t os = piv_size - index;
ssize_t os = piv_size - index;
alloc(piv_size + init_list.size());
if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index + init_list.size()),
reinterpret_cast<const void *>(piv_data + index),
os * sizeof(T));
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;
@@ -1391,16 +1384,13 @@ public:
inline PIVector<T> & remove(size_t index, size_t count = 1) {
if (count == 0) return *this;
if (index + count >= piv_size) {
if (index < piv_size) {
deleteT(piv_data + index, piv_size - index);
piv_size = index;
resize(index);
return *this;
}
} else {
const size_t os = piv_size - index - count;
deleteT(piv_data + index, count);
memmove(reinterpret_cast<void *>(piv_data + index), reinterpret_cast<const void *>(piv_data + index + count), os * sizeof(T));
size_t os = piv_size - index - count;
deleteT(&(piv_data[index]), count);
memmove((void*)(&(piv_data[index])), (const void*)(&(piv_data[index + count])), os * sizeof(T));
piv_size -= count;
}
return *this;
}
@@ -1410,7 +1400,7 @@ public:
//! \~english This operation is very fast and never fails.
//! \~russian Эта операция выполняется мгновенно без копирования памяти и никогда не дает сбоев.
inline void swap(PIVector<T> & v) {
piSwap<T *>(piv_data, v.piv_data);
piSwap<T*>(piv_data, v.piv_data);
piSwap<size_t>(piv_size, v.piv_size);
piSwap<size_t>(piv_rsize, v.piv_rsize);
}
@@ -1454,18 +1444,23 @@ public:
//! 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))`.
//! Функция сравнения, возвращает `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) {
inline PIVector<T> & sort(std::function<bool(const T &a, const T &b)> comp) {
std::sort(begin(), end(), comp);
return *this;
}
@@ -1487,9 +1482,9 @@ public:
//! \endcode
//! \~\sa \a reversed()
inline PIVector<T> & reverse() {
const size_t s2 = piv_size / 2;
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]);
piSwap<T>(piv_data[i], piv_data[piv_size-i-1]);
}
return *this;
}
@@ -1517,12 +1512,10 @@ public:
//! Если `add_size < 0`, то с конца массива удаляются элементы.
//! Если `add_size < 0` и в массиве меньше элементов чем указано, то массив становится пустым.
//! \~\sa \a resize()
inline PIVector<T> & enlarge(ssize_t add_size, const T & e = T()) {
const ssize_t ns = size_s() + add_size;
if (ns <= 0)
clear();
else
resize(size_t(ns), e);
inline PIVector<T> & enlarge(llong add_size, const T & e = T()) {
llong ns = size_s() + add_size;
if (ns <= 0) clear();
else resize(size_t(ns), e);
return *this;
}
@@ -1555,15 +1548,12 @@ public:
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIVector<T> & removeAll(const T & e) {
ssize_t j = indexOf(e);
if (j != -1) {
for (size_t i = j + 1; i < piv_size; ++i) {
if (piv_data[i] != e) {
piv_data[j++] = std::move(piv_data[i]);
for (ssize_t i = 0; i < size_s(); ++i) {
if (piv_data[i] == e) {
remove(i);
--i;
}
}
remove(j, piv_size - j);
}
return *this;
}
@@ -1579,15 +1569,12 @@ public:
//! \endcode
//! \~\sa \a remove(), \a removeOne(), \a removeWhere()
inline PIVector<T> & removeWhere(std::function<bool(const T & e)> test) {
ssize_t j = indexWhere(test);
if (j != -1) {
for (size_t i = j + 1; i < piv_size; ++i) {
if (!test(piv_data[i])) {
piv_data[j++] = std::move(piv_data[i]);
for (ssize_t i = 0; i < size_s(); ++i) {
if (test(piv_data[i])) {
remove(i);
--i;
}
}
remove(j, piv_size - j);
}
return *this;
}
@@ -1646,8 +1633,7 @@ public:
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a push_back()
inline PIVector<T> & push_back(std::initializer_list<T> init_list) {
if (init_list.size() == 0) return *this;
const size_t ps = piv_size;
size_t ps = piv_size;
alloc(piv_size + init_list.size());
newT(piv_data + ps, init_list.begin(), init_list.size());
return *this;
@@ -1660,14 +1646,13 @@ public:
//! \~russian Перегруженая функция.
//! \~\sa \a push_back()
inline PIVector<T> & push_back(const PIVector<T> & v) {
if (v.isEmpty()) return *this;
#ifndef NDEBUG
if (&v == this) {
fprintf(stderr, "error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
printf("error with PIVector<%s>::push_back\n", __PIP_TYPENAME__(T));
}
#endif
assert(&v != this);
const size_t ps = piv_size;
size_t ps = piv_size;
alloc(piv_size + v.piv_size);
newT(piv_data + ps, v.piv_data, v.piv_size);
return *this;
@@ -1698,7 +1683,7 @@ public:
//! 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); }
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` в конец массива.
@@ -1706,7 +1691,7 @@ public:
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a append()
inline PIVector<T> & append(T && e) { return push_back(std::move(e)); }
inline PIVector<T> & append(T && e) {return push_back(std::move(e));}
//! \~english Appends the given elements to the end of the array.
//! \~russian Добавляет элементы в конец массива.
@@ -1718,7 +1703,7 @@ public:
//! Добавляет элементы из
//! [списка инициализации 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); }
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` в конец массива.
@@ -1731,7 +1716,7 @@ public:
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & append(const PIVector<T> & v) { return push_back(v); }
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` в конец массива.
@@ -1742,7 +1727,7 @@ public:
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & operator<<(const T & e) { return push_back(e); }
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` в конец массива.
@@ -1753,7 +1738,7 @@ public:
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & operator<<(T && e) { return push_back(std::move(e)); }
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` в конец массива.
@@ -1764,7 +1749,7 @@ public:
//! piCout << v; // {1, 2, 3, 4, 5}
//! \endcode
//! \~\sa \a append()
inline PIVector<T> & operator<<(const PIVector<T> & v) { return push_back(v); }
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` в начало массива.
@@ -1782,7 +1767,10 @@ public:
//! piCout << v; // {5, 4, 1, 2, 3}
//! \endcode
//! \~\sa \a push_back(), \a append(), \a prepend(), \a insert()
inline PIVector<T> & push_front(const T & e) { return insert(0, e); }
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` в начало массива.
@@ -1790,7 +1778,10 @@ public:
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a push_front()
inline PIVector<T> & push_front(T && e) { return insert(0, std::move(e)); }
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` в начало массива.
@@ -1803,7 +1794,10 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a push_front()
inline PIVector<T> & push_front(const PIVector<T> & v) { return insert(0, v); }
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 Добавляет элементы в начало массива.
@@ -1815,7 +1809,10 @@ public:
//! Добавляет элементы из
//! [списка инициализации C++11](https://ru.cppreference.com/w/cpp/utility/initializer_list).
//! \~\sa \a append()
inline PIVector<T> & push_front(std::initializer_list<T> init_list) { return insert(0, init_list); }
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` в начало массива.
@@ -1833,7 +1830,7 @@ public:
//! 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); }
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` в начало массива.
@@ -1841,7 +1838,7 @@ public:
//! \~english Overloaded function.
//! \~russian Перегруженая функция.
//! \~\sa \a prepend()
inline PIVector<T> & prepend(T && e) { return push_front(std::move(e)); }
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` в начало массива.
@@ -1854,7 +1851,7 @@ public:
//! piCout << v; // {4, 5, 1, 2, 3}
//! \endcode
//! \~\sa \a prepend()
inline PIVector<T> & prepend(const PIVector<T> & v) { return push_front(v); }
inline PIVector<T> & prepend(const PIVector<T> & v) {return push_front(v);}
//! \~english Appends the given elements to the begin of the array.
//! \~russian Добавляет элементы в начало массива.
@@ -1866,7 +1863,7 @@ public:
//! Добавляет элементы из
//! [списка инициализации 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); }
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 Удаляет один элемент с конца массива.
@@ -1883,8 +1880,7 @@ public:
//! \~\sa \a pop_front(), \a take_back(), \a take_front()
inline PIVector<T> & pop_back() {
if (piv_size == 0) return *this;
deleteT(piv_data + piv_size - 1, 1);
piv_size = piv_size - 1;
resize(piv_size - 1);
return *this;
}
@@ -1919,7 +1915,7 @@ public:
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_back() {
const T e(back());
T e(back());
pop_back();
return e;
}
@@ -1934,7 +1930,7 @@ public:
//! \endcode
//! \~\sa \a take_front(), \a pop_back(), \a pop_front()
inline T take_front() {
const T e(front());
T e(front());
pop_front();
return e;
}
@@ -1948,10 +1944,9 @@ public:
//! piCout << v2; // {1, 2, 3}
//! \endcode
//! \~\sa \a map()
template<typename ST>
template <typename ST>
inline PIVector<ST> toType() const {
PIVector<ST> ret;
ret.reserve(piv_size);
PIVector<ST> ret; ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) {
ret << ST(piv_data[i]);
}
@@ -1959,9 +1954,9 @@ public:
}
//! \~english Returns a new array with all elements
//! that pass the test implemented by the provided function `bool test(const T & e)`.
//! that pass the test implemented by the provided function `test`.
//! \~russian Возвращает новый массив со всеми элементами,
//! прошедшими проверку, задаваемую в передаваемой функции `bool test(const T & e)`.
//! прошедшими проверку, задаваемую в передаваемой функции `test`.
//! \~\details
//! \~\code
//! PIVector<int> v{3, 2, 5, 2, 7};
@@ -1977,39 +1972,6 @@ public:
return ret;
}
//! \~english Same as \a filter() but with `index` parameter in `test`.
//! \~russian Аналогично \a filter() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filter()
inline PIVector<T> filterIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIVector<T> ret;
for (size_t i = 0; i < piv_size; ++i) {
if (test(i, piv_data[i])) ret << piv_data[i];
}
return ret;
}
//! \~english Same as \a filter() but from end to begin (from right to left).
//! \~russian Аналогично \a filter() но от конца до начала (справа на лево).
//! \~\sa \a filter()
inline PIVector<T> filterReverse(std::function<bool(const T & e)> test) const {
PIVector<T> ret;
for (ssize_t i = piv_size; i >= 0; --i) {
if (test(piv_data[i])) ret << piv_data[i];
}
return ret;
}
//! \~english Same as \a filterReverse() but with `index` parameter in `test`.
//! \~russian Аналогично \a filterReverse() но с параметром индекса `index` в функции `test`.
//! \~\sa \a filterReverse()
inline PIVector<T> filterReverseIndexed(std::function<bool(size_t index, const T & e)> test) const {
PIVector<T> ret;
for (ssize_t i = piv_size; i >= 0; --i) {
if (test(i, piv_data[i])) ret << piv_data[i];
}
return ret;
}
//! \~english Execute function `void f(const T & e)` for every element in array.
//! \~russian Выполняет функцию `void f(const T & e)` для каждого элемента массива.
//! \~\details
@@ -2050,63 +2012,6 @@ public:
return *this;
}
//! \~english Same as \a forEach() but with `index` parameter in `f`.
//! \~russian Аналогично \a forEach() но с параметром индекса `index` в функции `f`.
//! \~\sa \a forEach()
inline void forEachIndexed(std::function<void(size_t index, const T & e)> f) const {
for (size_t i = 0; i < piv_size; ++i) {
f(i, piv_data[i]);
}
}
//! \~english Same as \a forEachIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachIndexed()
inline PIVector<T> & forEachIndexed(std::function<void(size_t index, T & e)> f) {
for (size_t i = 0; i < piv_size; ++i) {
f(i, piv_data[i]);
}
return *this;
}
//! \~english Same as \a forEach() but from end to begin (from right to left).
//! \~russian Аналогично \a forEach() но от конца до начала (справа на лево).
//! \~\sa \a forEach()
inline void forEachReverse(std::function<void(const T & e)> f) const {
for (ssize_t i = piv_size; i >= 0; --i) {
f(piv_data[i]);
}
}
//! \~english Same as \a forEachReverse(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverse(), но позволяет изменять элементы массива.
//! \~\sa \a forEach(), \a forEachReverse()
inline PIVector<T> & forEachReverse(std::function<void(T & e)> f) {
for (ssize_t i = piv_size; i >= 0; --i) {
f(piv_data[i]);
}
return *this;
}
//! \~english Same as \a forEachIndexed() but from end to begin (from right to left).
//! \~russian Аналогично \a forEachIndexed() но от конца до начала (справа на лево).
//! \~\sa \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline void forEachReverseIndexed(std::function<void(size_t index, const T & e)> f) const {
for (ssize_t i = piv_size; i >= 0; --i) {
f(i, piv_data[i]);
}
}
//! \~english Same as \a forEachReverseIndexed(), but allows you to change the elements of the array.
//! \~russian Аналогично \a forEachReverseIndexed(), но позволяет изменять элементы массива.
//! \~\sa \a forEachReverseIndexed(), \a forEachIndexed(), \a forEachReverse(), \a forEach()
inline PIVector<T> & forEachReverseIndexed(std::function<void(size_t index, T & e)> f) {
for (ssize_t i = piv_size; i >= 0; --i) {
f(i, piv_data[i]);
}
return *this;
}
//! \~english Сreates a new array populated with the results
//! of calling a provided function `ST f(const T & e)` on every element in the calling array.
//! \~russian Создаёт новый массив с результатом вызова указанной функции
@@ -2121,73 +2026,18 @@ public:
//! \~\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"}
//! piCout << sl; {"1", "2", "3"}
//! \endcode
//! \~\sa \a forEach(), \a reduce()
template<typename ST>
template <typename ST>
inline PIVector<ST> map(std::function<ST(const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
PIVector<ST> ret; ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) {
ret << f(piv_data[i]);
}
return ret;
}
//! \~english Same as \a map() but with `index` parameter in `f`.
//! \~russian Аналогично \a map() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.mapIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"0", "1", "2"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIVector<ST> mapIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (size_t i = 0; i < piv_size; ++i) {
ret << f(i, piv_data[i]);
}
return ret;
}
//! \~english Same as \a map() but from end to begin (from right to left).
//! \~russian Аналогично \a map() но от конца до начала (справа на лево).
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.mapReverse<PIString>([](const int & i){return PIString::fromNumber(i);});
//! piCout << sl; // {"3", "2", "1"}
//! \endcode
//! \~\sa \a map()
template<typename ST>
inline PIVector<ST> mapReverse(std::function<ST(const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (ssize_t i = piv_size; i >= 0; --i) {
ret << f(piv_data[i]);
}
return ret;
}
//! \~english Same as \a mapReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a mapReverse() но с параметром индекса `index` в функции `f`.
//! \~\code
//! PIVector<int> v{1, 2, 3};
//! PIVector<PIString> sl = v.mapReverseIndexed<PIString>([](size_t index, const int & i){return PIString::fromNumber(index);});
//! piCout << sl; // {"2", "1", "0"}
//! \endcode
//! \~\sa \a mapReverse()
template<typename ST>
inline PIVector<ST> mapReverseIndexed(std::function<ST(size_t index, const T & e)> f) const {
PIVector<ST> ret;
ret.reserve(piv_size);
for (ssize_t i = piv_size; i >= 0; --i) {
ret << f(i, piv_data[i]);
}
return ret;
}
//! \~english Applies the function `ST f(const T & e, const ST & acc)`
//! to each element of the array (from left to right), returns one value.
//! \~russian Применяет функцию `ST f(const T & e, const ST & acc)`
@@ -2229,7 +2079,7 @@ public:
//! piCout << s; // 15
//! \endcode
//! \~\sa \a forEach(), \a map()
template<typename ST>
template <typename ST>
inline ST reduce(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < piv_size; ++i) {
@@ -2238,42 +2088,6 @@ public:
return ret;
}
//! \~english Same as \a reduce() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduce() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (size_t i = 0; i < piv_size; ++i) {
ret = f(i, piv_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduce() but from end to begin (from right to left).
//! \~russian Аналогично \a reduce() но от конца до начала (справа на лево).
//! \~\sa \a reduce()
template<typename ST>
inline ST reduceReverse(std::function<ST(const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = piv_size; i >= 0; --i) {
ret = f(piv_data[i], ret);
}
return ret;
}
//! \~english Same as \a reduceReverse() but with `index` parameter in `f`.
//! \~russian Аналогично \a reduceReverse() но с параметром индекса `index` в функции `f`.
//! \~\sa \a reduceReverse()
template<typename ST>
inline ST reduceReverseIndexed(std::function<ST(size_t index, const T & e, const ST & acc)> f, const ST & initial = ST()) const {
ST ret(initial);
for (ssize_t i = piv_size; i >= 0; --i) {
ret = f(i, piv_data[i], ret);
}
return ret;
}
//! \~english Changes the dimension of the array, creates a two-dimensional array from a one-dimensional array.
//! \~russian Изменяет размерность массива, из одномерного массива создает двухмерный.
//! \~\details
@@ -2295,24 +2109,24 @@ public:
//! \~\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) {
fprintf(stderr, "error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
if (rows*cols != piv_size) {
printf("error with PIVector<%s>::reshape\n", __PIP_TYPENAME__(T));
}
#endif
assert(rows * cols == piv_size);
assert(rows*cols == piv_size);
PIVector<PIVector<T>> ret;
if (isEmpty()) return ret;
ret.expand(rows);
ret.resize(rows);
if (order == ReshapeByRow) {
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 == ReshapeByColumn) {
for (size_t r = 0; r < rows; r++) {
ret[r].resize(cols);
for (size_t c = 0; c < cols; c++) {
ret[r][c] = piv_data[c * rows + r];
ret[r][c] = piv_data[c*rows + r];
}
}
}
@@ -2333,12 +2147,14 @@ public:
//! piCout << xv.flatten<int>(); // {1, 2, 3, 4, 5, 6}
//! \endcode
//! \~\sa \a map(), \a reduce(), \a reshape()
template<typename C, typename std::enable_if<std::is_same<T, PIVector<C>>::value, int>::type = 0>
template<typename C, typename std::enable_if<
std::is_same<T, PIVector<C>>::value
, int>::type = 0>
inline PIVector<C> flatten(ReshapeOrder order = ReshapeByRow) const {
PIVector<C> ret;
if (isEmpty()) return ret;
const size_t rows = size();
const size_t cols = at(0).size();
size_t rows = size();
size_t cols = at(0).size();
ret.reserve(rows * cols);
if (order == ReshapeByRow) {
for (size_t r = 0; r < rows; r++) {
@@ -2374,198 +2190,99 @@ public:
//! 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>
template<typename C, typename std::enable_if<
std::is_same<T, PIVector<C>>::value
, int>::type = 0>
inline PIVector<PIVector<C>> reshape(size_t rows, size_t cols, ReshapeOrder order = ReshapeByRow) const {
PIVector<C> fl = flatten<C>();
return fl.reshape(rows, cols, order);
}
//! \~english Divides an array into a two-dimensional array using the separator `separator`.
//! \~russian Разделяет массив на двумерный массив с помощью разделителя`separator`.
//! \~\code
//! PIVector<int> v{1, 2, 3, 99, 4, 5, 99, 6};
//! piCout << v.split(99); // {{1, 2, 3}, {4, 5}, {6}}
//! \endcode
//! \~\sa \a splitBySize()
inline PIVector<PIVector<T>> split(const T & separator) const {
PIVector<PIVector<T>> ret;
if (isEmpty()) return ret;
size_t start = 0;
ssize_t ci = indexOf(separator, start);
while (ci >= 0) {
ret << PIVector<T>(piv_data + start, ci - start);
start = ci + 1;
ci = indexOf(separator, start);
}
if (start < piv_size) {
ret << PIVector<T>(piv_data + start, piv_size - start);
}
return ret;
}
//! \~english Divides an array into a two-dimensional array in chunks of no more than `sz`.
//! \~russian Разделяет массив на двумерный массив по кускам не более чем `sz`.
//! \~\sa \a split()
inline PIVector<PIVector<T>> splitBySize(size_t sz) const {
PIVector<PIVector<T>> ret;
if (isEmpty() || sz == 0) return ret;
const size_t ch = piv_size / sz;
for (size_t i = 0; i < ch; ++i) {
ret << PIVector<T>(piv_data + sz * i, sz);
}
const size_t t = ch * sz;
if (t < piv_size) {
ret << PIVector<T>(piv_data + t, piv_size - t);
}
return ret;
}
//! \~english Cut sub-array of this array.
//! \~russian Вырезает подмассив, то есть кусок из текущего массива.
//! \~english
//! \param index - index of this array where sub-array starts
//! \param count - sub-array size
//! \~russian
//! \param index - индекс в текущем массиве, откуда начинётся подмассив
//! \param count - размер подмассива
//! \~\details
//! \~english
//! Index must be in range from `0` to `size()-1`.
//! If sub-array size more than this array size, than ends early.
//! \~russian
//! Индекс начала должен лежать в диапазоне от `0` до `size()-1`.
//! Если заданный размер подмассива превышает размер текущего массива,
//! то вернется подмассив меньшего размера (`size()-index-1`).
inline PIVector<T> takeRange(size_t index, size_t count) {
PIVector<T> ret;
if (index >= piv_size || count == 0) return ret;
if (index + count > piv_size) count = piv_size - index;
ret.alloc(count);
memcpy(reinterpret_cast<void *>(ret.piv_data), reinterpret_cast<const void *>(piv_data + index), count * sizeof(T));
const size_t os = piv_size - index - count;
if (os > 0) {
memmove(reinterpret_cast<void *>(piv_data + index), reinterpret_cast<const void *>(piv_data + index + count), os * sizeof(T));
piv_size -= count;
} else {
piv_size = index;
}
return ret;
}
private:
inline void _reset() {
piv_size = 0;
piv_rsize = 0;
piv_data = nullptr;
}
inline void _reset() {piv_size = piv_rsize = 0; piv_data = 0;}
inline size_t asize(size_t s) {
if (s == 0) return 0;
if (piv_rsize * 2 >= s && piv_rsize < s) {
return piv_rsize * 2;
if (piv_rsize + piv_rsize >= s && piv_rsize < s) {
return piv_rsize + piv_rsize;
}
ssize_t t = _PIContainerConstants<T>::minCountPoT();
s -= 1;
while (s >> t)
ssize_t t = _PIContainerConstants<T>::minCountPoT(), s_ = s - 1;
while (s_ >> t)
++t;
return (1 << t);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
for (size_t i = 0; i < s; ++i) {
for (size_t i = 0; i < s; ++i)
elementNew(dst + i, src[i]);
}
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void newT(T * dst, const T * src, size_t s) {
PIINTROSPECTION_CONTAINER_USED(T, s)
memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<const void *>(src), s * sizeof(T));
memcpy((void*)(dst), (const void*)(src), s * sizeof(T));
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
if (d != nullptr) {
if ((uchar*)d != 0) {
for (size_t i = 0; i < sz; ++i) {
elementDelete(d[i]);
}
}
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void deleteT(T * d, size_t sz) {
PIINTROSPECTION_CONTAINER_UNUSED(T, sz)
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, const T & from) {
new (to) T(from);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
new (to) T(std::move(from));
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {
(*to) = from;
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementNew(T * to, T && from) {
(*to) = std::move(from);
}
template<typename T1 = T, typename std::enable_if<!std::is_trivially_copyable<T1>::value, int>::type = 0>
inline void elementDelete(T & from) {
from.~T();
}
template<typename T1 = T, typename std::enable_if<std::is_trivially_copyable<T1>::value, int>::type = 0>
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, const T & from) {new(to)T(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {new(to)T(std::move(from));}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T1 * to, const T & from) {(*to) = from;}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementNew(T * to, T && from) {(*to) = std::move(from);}
template<typename T1 = T, typename std::enable_if<
!std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {from.~T();}
template<typename T1 = T, typename std::enable_if<
std::is_trivially_copyable<T1>::value
, int>::type = 0>
inline void elementDelete(T & from) {}
inline void dealloc() {
if (piv_data != nullptr) {
free(reinterpret_cast<void *>(piv_data));
piv_data = nullptr;
if ((uchar*)piv_data != 0) free((uchar*)piv_data);
piv_data = 0;
}
}
inline void expand(size_t new_size, const T & e = T()) {
const size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, e);
}
}
inline void expand(size_t new_size, std::function<T(size_t i)> f) {
const size_t os = piv_size;
alloc(new_size);
PIINTROSPECTION_CONTAINER_USED(T, (new_size - os))
for (size_t i = os; i < new_size; ++i) {
elementNew(piv_data + i, f(i));
}
}
inline void alloc(size_t new_size) {
if (new_size <= piv_rsize) {
piv_size = new_size;
return;
}
piv_size = new_size;
const size_t as = asize(new_size);
size_t as = asize(new_size);
if (as == piv_rsize) return;
PIINTROSPECTION_CONTAINER_ALLOC(T, (as - piv_rsize))
T * p_d = reinterpret_cast<T *>(realloc(reinterpret_cast<void *>(piv_data), as * sizeof(T)));
PIINTROSPECTION_CONTAINER_ALLOC(T, (as-piv_rsize))
T * p_d = (T*)(realloc((void*)(piv_data), as*sizeof(T)));
#ifndef NDEBUG
if (!p_d) {
fprintf(stderr, "error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
printf("error with PIVector<%s>::alloc\n", __PIP_TYPENAME__(T));
}
#endif
assert(p_d);
@@ -2573,9 +2290,8 @@ private:
piv_rsize = as;
}
T * piv_data = nullptr;
size_t piv_size = 0;
size_t piv_rsize = 0;
T * piv_data;
size_t piv_size, piv_rsize;
};
@@ -2583,7 +2299,7 @@ private:
//! \~english Output operator to [std::ostream](https://en.cppreference.com/w/cpp/io/basic_ostream).
//! \~russian Оператор вывода в [std::ostream](https://ru.cppreference.com/w/cpp/io/basic_ostream).
template<typename T>
inline std::ostream & operator<<(std::ostream & s, const PIVector<T> & v) {
inline std::ostream & operator <<(std::ostream & s, const PIVector<T> & v) {
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
@@ -2598,9 +2314,9 @@ inline std::ostream & operator<<(std::ostream & s, const PIVector<T> & v) {
//! \~english Output operator to \a PICout
//! \~russian Оператор вывода в \a PICout
template<typename T>
inline PICout operator<<(PICout s, const PIVector<T> & v) {
inline PICout operator <<(PICout s, const PIVector<T> & v) {
s.space();
s.saveAndSetControls(0);
s.setControl(0, true);
s << "{";
for (size_t i = 0; i < v.size(); ++i) {
s << v[i];
@@ -2609,13 +2325,11 @@ inline PICout operator<<(PICout s, const PIVector<T> & v) {
}
}
s << "}";
s.restoreControls();
s.restoreControl();
return s;
}
template<typename T>
inline void piSwap(PIVector<T> & f, PIVector<T> & s) {
f.swap(s);
}
inline void piSwap(PIVector<T> & f, PIVector<T> & s) {f.swap(s);}
#endif // PIVECTOR_H

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